Skip to content

Instantly share code, notes, and snippets.

@LaurentMT
Created September 25, 2024 14:19
Show Gist options
  • Save LaurentMT/891bc518bc94cc549e6af25647d66a4d to your computer and use it in GitHub Desktop.
Save LaurentMT/891bc518bc94cc549e6af25647d66a4d to your computer and use it in GitHub Desktop.
Verification of Ashigaru Wallet 1.0.0 codebase (WIP)
-------------------------
CHECK FIRST COMMIT: OK
-------------------------
I've been able to check the first commit of Ashigaru Wallet (http://ashicodepbnpvslzsl2bz7l2pwrjvajgumgac423pp3y2deprbnzz7id.onion/Ashigaru/Ashigaru-Mobile/src/commit/2fbad89bf357c99b852ba70aad74b52e72e395e2)
by comparing it with this commit of the Samourai Wallet Archive (https://github.com/Archive-Samourai-Wallet/samourai-wallet-android/tree/cc2b4492514d00de39b8390b7ca3792a284cb8f2)
I've selected this specific commit based on the statement made in the blog post (https://ashigaru.rs/news/release-wallet-v1-0-0/) that the new wallet was based on v0.99.98ii of Samourai Wallet)
Everything seems ok.
-------------------------
CHECK SECOND COMMIT: WIP
-------------------------
This commit requires a lot more work as it seems that many different things are done in this single commit:
- Content of the extlibj library in included in the repository of Ashigaru Wallet (it was previously stored in a separate repository)
- New code waiting in the develop branch of Samourai Wallet have been included in Ashigaru wallet
- Additional modifications done to the code of the wallet
I don't know why all these modifications have been merged with a single commit but it clearly makes peer review far more difficult. :(
EXTLIBJ CODE CHECK
-------------------------
Anyway, I've first checked the extlib repo by comparing the content of the extlibj directory found in the second commit of Ashigaru Wallet (http://ashicodepbnpvslzsl2bz7l2pwrjvajgumgac423pp3y2deprbnzz7id.onion/Ashigaru/Ashigaru-Mobile/src/commit/6b37843e5d1f7748836471cd1e3621a5fb1cc29f)
with this commit of the extlibj repo from the Samourai Wallet Archive (https://github.com/Archive-Samourai-Wallet/extlibj/tree/f57adf1a54d593ed624622476f4d78d85bec0c55).
I've converged to this commit after a few trials (startinf from v1.0.6) that were returning weird diffs between the 2 projects.
As far as I can tell, everything seems ok. The number of modifications is limited, each modification seems to make sense and doesn't seem malicious.
Here are the results of the diff comparing the directories and files:
$ diff -qrs /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/ /home/laurent/dev_samourai/extlibj/ | grep -v "are identical"
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/: build.gradle
Only in /home/laurent/dev_samourai/extlibj/: .git
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/.gitignore and /home/laurent/dev_samourai/extlibj/.gitignore differ
Only in /home/laurent/dev_samourai/extlibj/: java
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/: LICENSE
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/pom.xml and /home/laurent/dev_samourai/extlibj/pom.xml differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/README.md and /home/laurent/dev_samourai/extlibj/README.md differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/src: main
Only in /home/laurent/dev_samourai/extlibj/src: test
Only in /home/laurent/dev_samourai/extlibj/: target
Only in /home/laurent/dev_samourai/extlibj/: .travis.yml
$ diff -qrs /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/src/main/java/com/samourai/wallet/ /home/laurent/dev_samourai/extlibj/java/com/samourai/wallet/ | grep -v "are identical"
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/src/main/java/com/samourai/wallet/api/backend/BackendApi.java /home/laurent/dev_samourai/extlibj/java/com/samourai/wallet/api/backend/BackendApi.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/src/main/java/com/samourai/wallet/api/paynym/PaynymServer.java /home/laurent/dev_samourai/extlibj/java/com/samourai/wallet/api/paynym/PaynymServer.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/src/main/java/com/samourai/wallet/dexConfig/SamouraiConfig.java /home/laurent/dev_samourai/extlibj/java/com/samourai/wallet/dexConfig/SamouraiConfig.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/src/main/java/com/samourai/wallet/SamouraiWalletConst.java /home/laurent/dev_samourai/extlibj/java/com/samourai/wallet/SamouraiWalletConst.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/src/main/java/com/samourai/wallet/util/Util.java /home/laurent/dev_samourai/extlibj/java/com/samourai/wallet/util/Util.java differ
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/src/main/java/com/samourai/wallet/api/backend/BackendApi.java /home/laurent/dev_samourai/extlibj/java/com/samourai/wallet/api/backend/BackendApi.java
3,13c3
< import static org.apache.commons.lang3.StringUtils.stripEnd;
<
< import com.samourai.wallet.api.backend.beans.BackendPushTxException;
< import com.samourai.wallet.api.backend.beans.BackendPushTxResponse;
< import com.samourai.wallet.api.backend.beans.MultiAddrResponse;
< import com.samourai.wallet.api.backend.beans.TxDetail;
< import com.samourai.wallet.api.backend.beans.TxsResponse;
< import com.samourai.wallet.api.backend.beans.UnspentOutput;
< import com.samourai.wallet.api.backend.beans.UnspentResponse;
< import com.samourai.wallet.api.backend.beans.WalletResponse;
< import com.samourai.wallet.api.backend.beans.XPubResponse;
---
> import com.samourai.wallet.api.backend.beans.*;
24d13
<
29,35c18
< import java.util.ArrayList;
< import java.util.Arrays;
< import java.util.Collection;
< import java.util.HashMap;
< import java.util.LinkedHashMap;
< import java.util.List;
< import java.util.Map;
---
> import java.util.*;
91c74
< String url = computeAuthUrl(getStrippedUrlBackend() + URL_UNSPENT + zpubStr);
---
> String url = computeAuthUrl(urlBackend + URL_UNSPENT + zpubStr);
107c90
< String url = computeAuthUrl(getStrippedUrlBackend() + URL_MULTIADDR + zpubStr);
---
> String url = computeAuthUrl(urlBackend + URL_MULTIADDR + zpubStr);
144c127
< String url = computeAuthUrl(getStrippedUrlBackend() + URL_TXS + zpubStr+"&page="+page+"&count="+count);
---
> String url = computeAuthUrl(urlBackend + URL_TXS + zpubStr+"&page="+page+"&count="+count);
153c136
< String url = computeAuthUrl(getStrippedUrlBackend() + URL_TX + txid + (fees ? "?fees=1" : ""));
---
> String url = computeAuthUrl(urlBackend + URL_TX + txid + (fees ? "?fees=1" : ""));
163c146
< String url = computeAuthUrl(getStrippedUrlBackend() + URL_WALLET + zpubStr);
---
> String url = computeAuthUrl(urlBackend + URL_WALLET + zpubStr);
180c163
< String url = computeAuthUrl(getStrippedUrlBackend() + URL_XPUB + xpub);
---
> String url = computeAuthUrl(urlBackend + URL_XPUB + xpub);
193c176
< String url = computeAuthUrl(getStrippedUrlBackend() + URL_INIT_BIP84);
---
> String url = computeAuthUrl(urlBackend + URL_INIT_BIP84);
206c189
< String url = computeAuthUrl(getStrippedUrlBackend() + URL_MINER_FEES);
---
> String url = computeAuthUrl(urlBackend + URL_MINER_FEES);
218c201
< String url = computeAuthUrl(getStrippedUrlBackend() + URL_SEEN + Util.encodeUrl(addressesStr));
---
> String url = computeAuthUrl(urlBackend + URL_SEEN + Util.encodeUrl(addressesStr));
243c226
< String url = computeAuthUrl(getStrippedUrlBackend() + URL_PUSHTX);
---
> String url = computeAuthUrl(urlBackend + URL_PUSHTX);
326,329d308
< }
<
< public String getStrippedUrlBackend() {
< return stripEnd(urlBackend, "/");
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/src/main/java/com/samourai/wallet/api/paynym/PaynymServer.java /home/laurent/dev_samourai/extlibj/java/com/samourai/wallet/api/paynym/PaynymServer.java
4c4
< PAYNYM_IS("https://paynym.rs/api/v1");
---
> PAYNYM_IS("https://paynym.is/api/v1");
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/src/main/java/com/samourai/wallet/dexConfig/SamouraiConfig.java /home/laurent/dev_samourai/extlibj/java/com/samourai/wallet/dexConfig/SamouraiConfig.java
14,17c14,17
< private String sorobanServerTestnetClear = "https://soroban.paynym.rs/test";
< private String sorobanServerTestnetOnion = "http://ashi5c6obifqi2thzkxqrqlkewywzucgglusc3n7qusnei75nrkwwyad.onion:4242";
< private String sorobanServerMainnetClear = "https://soroban.paynym.rs";
< private String sorobanServerMainnetOnion = "http://ashi5c6obifqi2thzkxqrqlkewywzucgglusc3n7qusnei75nrkwwyad.onion:4242";
---
> private String sorobanServerTestnetClear = "https://soroban.samouraiwallet.com/test";
> private String sorobanServerTestnetOnion = "http://sorob4sg7yiopktgz4eom7hl5mcodr6quvhmdpljl5qqhmt6po7oebid.onion/test";
> private String sorobanServerMainnetClear = "https://soroban.samouraiwallet.com";
> private String sorobanServerMainnetOnion = "http://sorob4sg7yiopktgz4eom7hl5mcodr6quvhmdpljl5qqhmt6po7oebid.onion";
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/src/main/java/com/samourai/wallet/SamouraiWalletConst.java /home/laurent/dev_samourai/extlibj/java/com/samourai/wallet/SamouraiWalletConst.java
18,19c18,19
< public static final String SAAS_PCODE_MAINNET = "___";
< public static final String SAAS_PCODE_TESTNET = "____";
---
> public static final String SAAS_PCODE_MAINNET = "PM8TJUYeU1rF5zcVkNsiN6LEzikQXH4NTtgzL7bCbnznNtef5mWVi9i3LetDByv9HHMTq5czDppAP4gyimC7LyNLiC1hfAyQCHvDBP3EzPU5sx3yyxRY";
> public static final String SAAS_PCODE_TESTNET = "PM8TJXBr2UNrPuhTFrmiCrww74GCFm1WbTqpxEXACpfzAsKqM3xvgZPG2PhDGycW2Ud9RiCzVHb3NprRvGffpYbi9bw6sYjU5nZJm94syV1J67V9fRND";
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ExtLibJ/src/main/java/com/samourai/wallet/util/Util.java /home/laurent/dev_samourai/extlibj/java/com/samourai/wallet/util/Util.java
99,102d98
< public static String sha256ToString(byte[] b) {
< return new String(Hex.encodeHex(sha256(b)));
< }
<
WALLET CODE CHECK
-------------------------
In order to check the modifications done on the code of the wallet itself, I've compared the second commit of Ashigaru Wallet (http://ashicodepbnpvslzsl2bz7l2pwrjvajgumgac423pp3y2deprbnzz7id.onion/Ashigaru/Ashigaru-Mobile/src/commit/6b37843e5d1f7748836471cd1e3621a5fb1cc29f)
with the code of the develop branch in the Samourai Wallet Archive (https://github.com/Archive-Samourai-Wallet/samourai-wallet-android/tree/e7270d263d62775dc9ebecd27ab733b65c41aa8f)
The initial diff returns 286 entries (directories, files). This number can be reduced to 125 entries if we remove files that don't store code (images, layout files, etc).
Here are the result of the diff (with "static" files being marked as "OK"):
$ diff -qrs /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/ /home/laurent/dev_samourai/samourai-wallet-android/ | grep -v "are identical"
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/: accompanying-release-files
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/build.gradle and /home/laurent/dev_samourai/samourai-wallet-android/app/build.gradle differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/AndroidManifest.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/AndroidManifest.xml differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/http/client/AndroidHttpClient.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/http/client/AndroidHttpClient.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/api/APIFactory.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/api/APIFactory.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/api/fee/EnumFeeRepresentation.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/api/fee/EnumFeeRepresentation.java differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/api: ping
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/api: txs
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/api: wallet
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/api: xpub
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/bip47/BIP47Meta.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/bip47/BIP47Meta.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/bip47/BIP47Util.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/bip47/BIP47Util.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/bip47/paynym/WebUtil.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/bip47/paynym/WebUtil.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/bip47/SendNotifTxFactory.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/bip47/SendNotifTxFactory.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/collaborate/CollaborateActivity.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/collaborate/CollaborateActivity.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/collaborate/ParticipateSegment.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/collaborate/ParticipateSegment.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/collaborate/Paynym.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/collaborate/Paynym.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/collaborate/TransactionSetup.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/collaborate/TransactionSetup.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/collaborate/viewmodels/CahootsTransactionViewModel.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/collaborate/viewmodels/CahootsTransactionViewModel.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/collaborate/viewmodels/CollaborateViewModel.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/collaborate/viewmodels/CollaborateViewModel.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/CreateWalletActivity.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/CreateWalletActivity.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/explorer/ExplorerActivity.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/explorer/ExplorerActivity.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/fragments/PaynymSelectModalFragment.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/fragments/PaynymSelectModalFragment.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/home/AccountSelectionActivity.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/home/AccountSelectionActivity.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/home/BalanceActivity.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/home/BalanceActivity.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/home/BalanceViewModel.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/home/BalanceViewModel.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/MainActivity2.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/MainActivity2.java differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/network/dojo: DojoDetailsActivity.kt
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/network/dojo: DojoQRBottomsheet.kt
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/network/dojo/DojoUtil.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/network/dojo/DojoUtil.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/network/NetworkDashboard.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/network/NetworkDashboard.java differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard: CreateOrRestoreActivity.kt
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard: OfflineDojoActivityScreen.kt
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard/OnBoardSlidesActivity.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/onboard/OnBoardSlidesActivity.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard/RestoreOptionActivity.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/onboard/RestoreOptionActivity.kt differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard: SetDojoActivity.kt
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard/SetUpWalletActivity.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/onboard/SetUpWalletActivity.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard/SetUpWalletViewModel.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/onboard/SetUpWalletViewModel.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/pairing/PairingMenu.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/pairing/PairingMenu.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/payload/ExternalBackupManager.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/payload/ExternalBackupManager.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/payload/PayloadUtil.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/payload/PayloadUtil.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/addPaynym/AddPaynymActivity.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/addPaynym/AddPaynymActivity.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/api/PayNymApiService.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/api/PayNymApiService.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/fragments/EditPaynymBottomSheet.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/fragments/EditPaynymBottomSheet.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/fragments/PaynymListFragment.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/fragments/PaynymListFragment.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/paynymDetails/PayNymDetailsActivity.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/paynymDetails/PayNymDetailsActivity.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/PayNymHome.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/PayNymHome.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/PayNymViewModel.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/PayNymViewModel.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/pin/PinEntryActivity.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/pin/PinEntryActivity.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/pin/PinEntryManager.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/pin/PinEntryManager.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/ReceiveActivity.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/ReceiveActivity.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/RecoveryWordsActivity.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/RecoveryWordsActivity.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/RestoreSeedWalletActivity.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/RestoreSeedWalletActivity.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/ricochet/RicochetMeta.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/ricochet/RicochetMeta.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/SamouraiActivity.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/SamouraiActivity.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/SamouraiApplication.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/SamouraiApplication.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/SamouraiWallet.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/SamouraiWallet.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/batch/BatchSpendActivity.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/batch/BatchSpendActivity.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/cahoots/SelectCahootsType.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/cahoots/SelectCahootsType.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/FeeUtil.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/FeeUtil.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/broadcast/SpendRicochetTxBroadcaster.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/broadcast/SpendRicochetTxBroadcaster.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/CoinSelectionManagerBottomSheet.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/CoinSelectionManagerBottomSheet.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/preview/BatchPreviewTx.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/preview/BatchPreviewTx.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/preview/CustomPreviewTx.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/preview/CustomPreviewTx.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/preview/RicochetCustomPreviewTx.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/preview/RicochetCustomPreviewTx.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/preview/RicochetPreviewTx.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/preview/RicochetPreviewTx.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/preview/SimplePreviewTx.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/preview/SimplePreviewTx.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/preview/StonewallPreviewTx.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/preview/StonewallPreviewTx.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/ref/EnumTransactionPriority.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/ref/EnumTransactionPriority.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/ref/EnumTxAlert.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/ref/EnumTxAlert.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/ReviewTxActivity.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/ReviewTxActivity.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/ReviewTxAlert.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/ReviewTxAlert.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/ReviewTxFeeManagerBottomSheet.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/ReviewTxFeeManagerBottomSheet.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/ReviewTxModel.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/ReviewTxModel.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/sendbutton/SwipeSendButton.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/sendbutton/SwipeSendButton.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/SendActivity.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/SendActivity.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/service/WalletRefreshWorker.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/service/WalletRefreshWorker.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/service/WebSocketHandler.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/service/WebSocketHandler.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/service/WebSocketService.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/service/WebSocketService.java differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/settings: CustomPreference.java
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/settings/SettingsActivity.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/settings/SettingsActivity.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/settings/SettingsDetailsFragment.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/settings/SettingsDetailsFragment.kt differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet: sync
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/theme/Color.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/theme/Color.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tools/Auth47BottomSheet.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tools/Auth47BottomSheet.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tools/BroadcastHexBottomSheet.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tools/BroadcastHexBottomSheet.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tools/SignPSBTBottomSheet.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tools/SignPSBTBottomSheet.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tools/SweepPrivateKey.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tools/SweepPrivateKey.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tools/ToolsBottomSheet.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tools/ToolsBottomSheet.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tools/viewmodels/SweepViewModel.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tools/viewmodels/SweepViewModel.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tor/kpm/TorKmpManager.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tor/kpm/TorKmpManager.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tor/SamouraiTorManager.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tor/SamouraiTorManager.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tx/TxDetailsActivity.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tx/TxDetailsActivity.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/activity/ActivityHelper.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/activity/ActivityHelper.java differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util: AppUpdateAvailableBottomSheet.kt
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/func/AddressHelper.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/func/AddressHelper.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/func/BatchSendUtil.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/func/BatchSendUtil.java differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/func: PaymentCodeHelper.java
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/func/PayNymUtil.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/func/PayNymUtil.kt differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/func: WalletRefreshUtil.kt
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/func/WalletUtil.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/func/WalletUtil.java differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/network: AshigaruNetworkException.java
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/network/BackendApiAndroid.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/network/BackendApiAndroid.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/network/BlockExplorerUtil.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/network/BlockExplorerUtil.java differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/network: DojoNetworkUtils.kt
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/network/WebUtil.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/network/WebUtil.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/PrefsUtil.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/PrefsUtil.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/tech/AppUtil.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/tech/AppUtil.java differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/tech: AshigaruException.java
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/tech/HapticHelper.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/tech/HapticHelper.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/tech/SimpleTaskRunner.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/tech/SimpleTaskRunner.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/tech/ThreadHelper.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/tech/ThreadHelper.java differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/tech: VerifyPGPSignedClearMessageUtil.java
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/view/SamCheckbox.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/view/SamCheckbox.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/utxos/UTXODetailsActivity.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/utxos/UTXODetailsActivity.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/utxos/UTXOSActivity.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/utxos/UTXOSActivity.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/whirlpool/newPool/fragments/SelectPoolFragment.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/whirlpool/newPool/fragments/SelectPoolFragment.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/whirlpool/WhirlpoolHome.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/whirlpool/WhirlpoolHome.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/whirlpool/WhirlPoolHomeViewModel.kt and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/whirlpool/WhirlPoolHomeViewModel.kt differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/widgets/TransactionProgressView.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/widgets/TransactionProgressView.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/whirlpool/client/wallet/data/AndroidMinerFeeSupplier.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/whirlpool/client/wallet/data/AndroidMinerFeeSupplier.java differ
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ashigaru_standing.png
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable/divider_grey.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable/divider_grey.xml differ
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: dojo_logo.png
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_alert_box.xml
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_ashigaru_logo.png
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_ashigaru_tor_connected.png
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_ashigaru_tor_data_transfer.png
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_ashigaru_tor_idle.png
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_checkbox_blank_outline.xml
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_checkbox_marked.xml
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_check.xml
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_close_box.xml
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_layers_triple.xml
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable/ic_network_check_black_24dp.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable/ic_network_check_black_24dp.xml differ
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_piggy_bank.xml
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_plus_icon.xml
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable: ic_samourai_logo_splash_vect.xml
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable: ic_samourai_logo.xml
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable: ic_samourai_mono_launcher_icon.xml
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable: ic_samourai_tor_data_transfer.xml
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable: ic_samourai_tor_enabled.xml
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable: ic_samourai_tor_idle.xml
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_sync.xml
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: ic_whirlpool_v2.xml
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable: launch_screen.xml
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: notes_scroll.xml
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: qrcode_scan.xml
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: rounded_rectangle_bottom_sheet.xml
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: rounded_rectangle.xml
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable/samourai_splash.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable/samourai_splash.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable/tag_round_shape.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable/tag_round_shape.xml differ
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable: utxo_list.xml
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res: drawable-anydpi
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-hdpi: ic_crop_free_white_24dp.png
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable-hdpi/ic_launcher_round.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-hdpi/ic_launcher_round.png differ
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-hdpi: ic_samourai_logo_splash.png
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable-hdpi: ic_sync_in_progress.png
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-hdpi: samourai_logo_splash.png
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: drawable-ldpi
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-mdpi: ic_crop_free_white_24dp.png
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable-mdpi/ic_launcher_round.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-mdpi/ic_launcher_round.png differ
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-mdpi: ic_samourai_logo_splash.png
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable-mdpi: ic_sync_in_progress.png
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-mdpi: samourai_logo_splash.png
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: drawable-v23
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-xhdpi: ic_crop_free_white_24dp.png
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable-xhdpi/ic_launcher_round.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-xhdpi/ic_launcher_round.png differ
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-xhdpi: ic_samourai_logo_splash.png
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable-xhdpi: ic_sync_in_progress.png
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-xhdpi: samourai_logo_splash.png
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-xxhdpi: ic_crop_free_white_24dp.png
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable-xxhdpi/ic_launcher_round.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-xxhdpi/ic_launcher_round.png differ
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-xxhdpi: ic_samourai_logo_splash.png
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable-xxhdpi: ic_sync_in_progress.png
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-xxhdpi: samourai_logo_splash.png
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-xxxhdpi: ic_crop_free_white_24dp.png
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/drawable-xxxhdpi/ic_launcher_round.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-xxxhdpi/ic_launcher_round.png differ
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-xxxhdpi: ic_samourai_logo_splash.png
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/drawable-xxxhdpi: samourai_logo_splash.png
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/activity_add_paynym.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/activity_add_paynym.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/activity_balance.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/activity_balance.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/activity_create_wallet.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/activity_create_wallet.xml differ
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout: activity_dojo_details.xml
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/activity_main.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/activity_main.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/activity_network_dashboard.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/activity_network_dashboard.xml differ
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout: activity_offline_mode_dojo.xml
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/activity_on_board_slides.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/activity_on_board_slides.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/activity_pairing_menu.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/activity_pairing_menu.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/activity_paynym_details.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/activity_paynym_details.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/activity_receive.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/activity_receive.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/activity_restore_option.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/activity_restore_option.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/activity_restore_wallet_activity.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/activity_restore_wallet_activity.xml differ
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout: activity_set_dojo.xml
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/activity_set_up_wallet.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/activity_set_up_wallet.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/activity_tx.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/activity_tx.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/bottomsheet_edit_paynym.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/bottomsheet_edit_paynym.xml differ
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout: create_or_restore.xml
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/fragment_choose_cahoots_type.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/fragment_choose_cahoots_type.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/fragment_choose_pools.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/fragment_choose_pools.xml differ
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout: fragment_dojo_bottomsheet.xml
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/fragment_import_wallet.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/fragment_import_wallet.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/paynym_list_item.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/paynym_list_item.xml differ
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout: release_notes_content.xml
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/send_transaction_main_segment.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/send_transaction_main_segment.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/transaction_progress_view.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/transaction_progress_view.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/tx_item_layout_.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/tx_item_layout_.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout/tx_item_section_layout.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/layout/tx_item_section_layout.xml differ
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/layout: update_available_content.xml
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/menu/batch_menu.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/menu/batch_menu.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/menu/bip47_menu.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/menu/bip47_menu.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/menu/home_tools_menu.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/menu/home_tools_menu.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/menu/main.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/menu/main.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/menu/receive_activity_menu.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/menu/receive_activity_menu.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/menu/send_menu.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/menu/send_menu.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/menu/utxo_details_action_menu.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/menu/utxo_details_action_menu.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/menu/utxo_details_menu.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/menu/utxo_details_menu.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/menu/whirlpool_main.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/menu/whirlpool_main.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-hdpi/ic_launcher.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-mdpi/ic_launcher.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/values/attrs_tor_kmp.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/values/attrs_tor_kmp.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/values/colors.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/values/colors.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/values/dimens.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/values/dimens.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/values/ic_launcher_background.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/values/ic_launcher_background.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/values/strings.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/values/strings.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/values/styles.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/values/styles.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/values/themes.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/values/themes.xml differ
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-bg
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-cn
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-cs
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-de
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-es
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-fr
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-hu
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-id
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-ir
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-it
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-my
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-nl
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-pt
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-pt-rBR
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-ru
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-sk
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-tr
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res: values-zh-rCN
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/xml/settings_other.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/xml/settings_other.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/xml/settings_troubleshoot.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/xml/settings_troubleshoot.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/xml/settings_txs.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/xml/settings_txs.xml differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/res/xml/settings_wallet.xml and /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/res/xml/settings_wallet.xml differ
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/test/java/com/samourai/wallet/util: VerifyPGPSignedClearMessageUtilTest.java
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/test/java/com/samourai/whirlpool/client/wallet/AbstractWhirlpoolTest.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/test/java/com/samourai/whirlpool/client/wallet/AbstractWhirlpoolTest.java differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/test/java/com/samourai/whirlpool/client/wallet/WhirlpoolWalletTest.java and /home/laurent/dev_samourai/samourai-wallet-android/app/src/test/java/com/samourai/whirlpool/client/wallet/WhirlpoolWalletTest.java differ
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/: ashigaru.api
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/build.gradle and /home/laurent/dev_samourai/samourai-wallet-android/build.gradle differ
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/: docs
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/: ExtLibJ
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/: .git
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/.gitignore and /home/laurent/dev_samourai/samourai-wallet-android/.gitignore differ
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/.gradle: 8.2
OK - Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/.gradle: 8.9
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/.gradle/buildOutputCleanup/buildOutputCleanup.lock and /home/laurent/dev_samourai/samourai-wallet-android/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/.gradle/buildOutputCleanup/cache.properties and /home/laurent/dev_samourai/samourai-wallet-android/.gradle/buildOutputCleanup/cache.properties differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/gradle/wrapper/gradle-wrapper.jar and /home/laurent/dev_samourai/samourai-wallet-android/gradle/wrapper/gradle-wrapper.jar differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/gradle/wrapper/gradle-wrapper.properties and /home/laurent/dev_samourai/samourai-wallet-android/gradle/wrapper/gradle-wrapper.properties differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/gradlew and /home/laurent/dev_samourai/samourai-wallet-android/gradlew differ
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/gradlew.bat and /home/laurent/dev_samourai/samourai-wallet-android/gradlew.bat differ
OK - Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/README.md and /home/laurent/dev_samourai/samourai-wallet-android/README.md differ
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/: ReproducibleBuilds.md
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/: samourai.api
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/: Samourai-Wallet-features.md
Files /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/settings.gradle and /home/laurent/dev_samourai/samourai-wallet-android/settings.gradle differ
OK - Only in /home/laurent/dev_samourai/samourai-wallet-android/: .travis.yml
WALLET CODE CHECK - REMAINING 125 ENTRIES
-----------------------------------------
The diff for the remaining 125 entries (what I haven't checked yet) are:
New files and directories
-------------------------
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/api: ping
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/api: txs
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/api: wallet
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/api: xpub
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/network/dojo: DojoDetailsActivity.kt
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/network/dojo: DojoQRBottomsheet.kt
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard: CreateOrRestoreActivity.kt
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard: OfflineDojoActivityScreen.kt
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard: SetDojoActivity.kt
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/func: PaymentCodeHelper.java
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/settings: CustomPreference.java
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet: sync
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util: AppUpdateAvailableBottomSheet.kt
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/func: WalletRefreshUtil.kt
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/network: AshigaruNetworkException.java
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/network: DojoNetworkUtils.kt
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/tech: AshigaruException.java
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/tech: VerifyPGPSignedClearMessageUtil.java
Only in /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/test/java/com/samourai/wallet/util: VerifyPGPSignedClearMessageUtilTest.java
Changed files
-------------------------
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/AndroidManifest.xml /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/AndroidManifest.xml
52d51
< android:screenOrientation="portrait"
70d68
< android:screenOrientation="portrait"
76d73
< android:screenOrientation="portrait"
92d88
< android:screenOrientation="portrait"
99d94
< android:screenOrientation="portrait"
106d100
< android:screenOrientation="portrait"
113d106
< android:screenOrientation="portrait"
128d120
< android:screenOrientation="portrait"
143d134
< android:screenOrientation="portrait"
158d148
< android:screenOrientation="portrait"
163d152
< android:screenOrientation="portrait"
168d156
< android:screenOrientation="portrait"
185d172
< android:screenOrientation="portrait"
191d177
< android:screenOrientation="portrait"
197d182
< android:screenOrientation="portrait"
204d188
< android:screenOrientation="portrait"
208,224d191
< android:screenOrientation="portrait"
< android:name=".onboard.SetDojoActivity"
< android:theme="@style/Theme.Samourai.Material" />
< <activity
< android:screenOrientation="portrait"
< android:name=".network.dojo.DojoDetailsActivity"
< android:theme="@style/Theme.Samourai.Material" />
< <activity
< android:screenOrientation="portrait"
< android:name=".onboard.OfflineDojoActivityScreen"
< android:theme="@style/Theme.Samourai.Material" />
< <activity
< android:screenOrientation="portrait"
< android:name=".onboard.CreateOrRestoreActivity"
< android:theme="@style/Theme.Samourai.Material" />
< <activity
< android:screenOrientation="portrait"
228d194
< android:screenOrientation="portrait"
232d197
< android:screenOrientation="portrait"
236d200
< android:screenOrientation="portrait"
241d204
< android:screenOrientation="portrait"
247d209
< android:screenOrientation="portrait"
253d214
< android:screenOrientation="portrait"
259d219
< android:screenOrientation="portrait"
264d223
< android:screenOrientation="portrait"
269d227
< android:screenOrientation="portrait"
274d231
< android:screenOrientation="portrait"
277,283c234
< android:theme="@style/Theme.Samourai.Material"
< android:launchMode="singleTask" />
< <activity
< android:screenOrientation="portrait"
< android:name=".sync.SyncWalletActivity"
< android:theme="@style/SamouraiAppSyncWallet"
< android:launchMode="singleTask" />
---
> android:theme="@style/Theme.Samourai.Material" />
285d235
< android:screenOrientation="portrait"
289d238
< android:screenOrientation="portrait"
294d242
< android:screenOrientation="portrait"
301d248
< android:screenOrientation="portrait"
307d253
< android:screenOrientation="portrait"
309c255,256
< android:label="@string/app_name" />
---
> android:label="@string/app_name"
> android:screenOrientation="landscape" />
311d257
< android:screenOrientation="portrait"
315,316c261
< android:theme="@style/Theme.Samourai.Material"
< android:launchMode="singleTask" />
---
> android:theme="@style/Theme.Samourai.Material" />
318d262
< android:screenOrientation="portrait"
323d266
< android:screenOrientation="portrait"
328d270
< android:screenOrientation="portrait"
332d273
< android:screenOrientation="portrait"
336d276
< android:screenOrientation="portrait"
340d279
< android:screenOrientation="portrait"
344d282
< android:screenOrientation="portrait"
350d287
< android:screenOrientation="portrait"
355d291
< android:screenOrientation="portrait"
363d298
< android:screenOrientation="portrait"
368d302
< android:screenOrientation="portrait"
373d306
< android:screenOrientation="portrait"
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/http/client/AndroidHttpClient.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/http/client/AndroidHttpClient.java
80c80,84
< return webUtil.tor_postURL(url, jsonBody, headers);
---
> if (SamouraiTorManager.INSTANCE.isRequired()) {
> return webUtil.tor_postURL(url, jsonBody, headers);
> } else {
> return webUtil.postURL(WebUtil.CONTENT_TYPE_APPLICATION_JSON, url, jsonBody, headers);
> }
85c89,96
< return webUtil.tor_postURL(url, body, headers);
---
> if (SamouraiTorManager.INSTANCE.isRequired()) {
> // tor enabled
> return webUtil.tor_postURL(url, body, headers);
> } else {
> // tor disabled
> String jsonString = queryString(body);
> return webUtil.postURL(null, url, jsonString, headers);
> }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/api/APIFactory.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/api/APIFactory.java
19d18
< import androidx.annotation.NonNull;
24d22
< import com.google.common.collect.ImmutableListMultimap;
26d23
< import com.google.common.collect.ListMultimap;
28,29d24
< import com.google.common.collect.MultimapBuilder;
< import com.google.common.collect.Multimaps;
57d51
< import com.samourai.wallet.util.func.EnumAddressType;
264,271c258,262
< try {
< byte[] xorSegments0 = Base64.decode(BuildConfig.XOR_1);
< byte[] xorSegments1 = Base64.decode(BuildConfig.XOR_2);
< return xor(xorSegments0, xorSegments1);
< } catch (final Exception e) {
< return null;
< }
< } else {
---
> byte[] xorSegments0 = Base64.decode(BuildConfig.XOR_1);
> byte[] xorSegments1 = Base64.decode(BuildConfig.XOR_2);
> return xor(xorSegments0, xorSegments1);
> }
> else {
401,414c392
< public synchronized JSONObject getXPUB(
< final Collection<String> addresses,
< final boolean parse) {
<
< return getXPUB(
< ImmutableListMultimap.<EnumAddressType, String>builder()
< .putAll(EnumAddressType.BIP44_LEGACY, addresses)
< .build(),
< parse);
< }
<
< private synchronized JSONObject getXPUB(
< final ListMultimap<EnumAddressType, String> addressesByType,
< final boolean parse) {
---
> private synchronized JSONObject getXPUB(String[] xpubs, boolean parse) {
416c394
< final String walletapiService = BackendApiAndroid.getApiServiceUrl("wallet?");
---
> String _url = WebUtil.getAPIUrl(context);
429,452c407,409
< final StringBuilder args = new StringBuilder();
< for (final EnumAddressType type : addressesByType.keySet()) {
< switch (type) {
< case BIP44_LEGACY:
< args.append("active=");
< args.append(StringUtils.join(addressesByType.get(type), URLEncoder.encode("|", "UTF-8")));
< args.append("&");
< break;
< case BIP49_SEGWIT_COMPAT:
< args.append("bip49=");
< args.append(StringUtils.join(addressesByType.get(type), URLEncoder.encode("|", "UTF-8")));
< args.append("&");
< break;
< case BIP84_SEGWIT_NATIVE:
< args.append("bip84=");
< args.append(StringUtils.join(addressesByType.get(type), URLEncoder.encode("|", "UTF-8")));
< args.append("&");
< break;
< default:
< info("APIFactory", "unknown EnumAddressType:" + type);
< break;
< }
< }
<
---
> StringBuilder args = new StringBuilder();
> args.append("active=");
> args.append(StringUtils.join(xpubs, URLEncoder.encode("|", "UTF-8")));
454c411
< args.append("at=");
---
> args.append("&at=");
456c413
< response = WebUtil.getInstance(context).postURL(walletapiService, args.toString());
---
> response = WebUtil.getInstance(context).postURL(_url + "wallet?", args.toString());
460,478c417,418
< final Map<String,String> args = Maps.newHashMap();
<
< for (final EnumAddressType type : addressesByType.keySet()) {
< switch (type) {
< case BIP44_LEGACY:
< args.put("active", StringUtils.join(addressesByType.get(type), "|"));
< break;
< case BIP49_SEGWIT_COMPAT:
< args.put("bip49", StringUtils.join(addressesByType.get(type), "|"));
< break;
< case BIP84_SEGWIT_NATIVE:
< args.put("bip84", StringUtils.join(addressesByType.get(type), "|"));
< break;
< default:
< info("APIFactory", "unknown EnumAddressType:" + type);
< break;
< }
< }
<
---
> HashMap<String,String> args = new HashMap<String,String>();
> args.put("active", StringUtils.join(xpubs, "|"));
482c422
< response = WebUtil.getInstance(context).tor_postURL(walletapiService, args);
---
> response = WebUtil.getInstance(context).tor_postURL(_url + "wallet", args);
491,492c431
<
< xpub_txs.put(ImmutableList.copyOf(addressesByType.values()).get(0), new ArrayList<Tx>());
---
> xpub_txs.put(xpubs[0], new ArrayList<Tx>());
513,516c452,454
< public synchronized JSONObject registerXPUB(
< final String xpub,
< final int purpose,
< final String tag) {
---
> private synchronized JSONObject registerXPUB(String xpub, int purpose, String tag) {
>
> String _url = WebUtil.getAPIUrl(context);
551,552c489
< final String xpubApiService = BackendApiAndroid.getApiServiceUrl("xpub?");
< response = WebUtil.getInstance(context).postURL(xpubApiService, args.toString());
---
> response = WebUtil.getInstance(context).postURL(_url + "xpub?", args.toString());
554c491,492
< } else {
---
> }
> else {
575,576c513
< final String xpubApiService = BackendApiAndroid.getApiServiceUrl("xpub");
< response = WebUtil.getInstance(context).tor_postURL(xpubApiService, args);
---
> response = WebUtil.getInstance(context).tor_postURL(_url + "xpub", args);
899a837,838
> String _url = WebUtil.getAPIUrl(context);
>
911,912c850
< xpub.equals(BIP84Util.getInstance(context).getWallet().getAccount(WhirlpoolMeta.getInstance(context).getWhirlpoolPostmix()).zpubstr()) ||
< xpub.equals(BIP84Util.getInstance(context).getWallet().getAccount(RicochetMeta.getInstance(context).getRicochetAccount()).zpubstr())
---
> xpub.equals(BIP84Util.getInstance(context).getWallet().getAccount(WhirlpoolMeta.getInstance(context).getWhirlpoolPostmix()).zpubstr())
927,929d864
< else if(tag != null && tag.equals(PrefsUtil.XPUBRICOCHETLOCK)) {
< addr = BIP84Util.getInstance(context).getWallet().getAccount(RicochetMeta.getInstance(context).getRicochetAccount()).getChange().getAddressAt(0);
< }
969,970c904
< final String xpubApiService = BackendApiAndroid.getApiServiceUrl("xpub/" + xpub + "/lock/");
< response = WebUtil.getInstance(context).postURL(xpubApiService , args.toString());
---
> response = WebUtil.getInstance(context).postURL(_url + "xpub/" + xpub + "/lock/", args.toString());
972c906,907
< } else {
---
> }
> else {
978c913
< info("APIFactory", "lock XPUB:" + BackendApiAndroid.getApiBaseUrl());
---
> info("APIFactory", "lock XPUB:" + _url);
980,981c915
< final String xpubApiService = BackendApiAndroid.getApiServiceUrl("xpub/" + xpub + "/lock/");
< response = WebUtil.getInstance(context).tor_postURL(xpubApiService, args);
---
> response = WebUtil.getInstance(context).tor_postURL(_url + "xpub/" + xpub + "/lock/", args);
1044c978,980
< public Pair<String, JSONObject> getNotifTx(String hash, String addr) {
---
> public JSONObject getNotifTx(String hash, String addr) {
>
> String _url = WebUtil.getAPIUrl(context);
1047d982
< String pcode = null;
1050c985,987
< StringBuilder url = new StringBuilder(BackendApiAndroid.getApiServiceUrl("tx/" + hash));
---
> StringBuilder url = new StringBuilder(_url);
> url.append("tx/");
> url.append(hash);
1059c996
< pcode = parseNotifTx(jsonObject, addr, hash);
---
> parseNotifTx(jsonObject, addr, hash);
1071c1008
< return isNull(jsonObject) ? null : new Pair<>(pcode, jsonObject);
---
> return jsonObject;
1075a1013,1014
> String _url = WebUtil.getAPIUrl(context);
>
1079,1080c1018,1019
< StringBuilder url = new StringBuilder(BackendApiAndroid.getApiServiceUrl("wallet"));
< url.append("?active=");
---
> StringBuilder url = new StringBuilder(_url);
> url.append("wallet?active=");
1132c1071
< public String parseNotifTx(JSONObject jsonObject, String addr, String hash) throws JSONException {
---
> public void parseNotifTx(JSONObject jsonObject, String addr, String hash) throws JSONException {
1137,1138d1075
< String pcodeAsString = null;
<
1228,1229c1165
< pcodeAsString = pcode.toString();
< info("APIFactory", "incoming payment code:" + pcodeAsString);
---
> info("APIFactory", "incoming payment code:" + pcode.toString());
1231,1233c1167,1168
< if(!pcodeAsString.equals(BIP47Util.getInstance(context).getPaymentCode().toString()) &&
< pcode.isValid() && !BIP47Meta.getInstance().incomingExists(pcodeAsString)) {
< BIP47Meta.getInstance().setLabel(pcodeAsString, "");
---
> if(!pcode.toString().equals(BIP47Util.getInstance(context).getPaymentCode().toString()) && pcode.isValid() && !BIP47Meta.getInstance().incomingExists(pcode.toString())) {
> BIP47Meta.getInstance().setLabel(pcode.toString(), "");
1254,1257c1189,1191
< final String receivePubKey = BIP47Util.getInstance(context).getReceivePubKey(pcode, i);
< info("APIFactory", "receive from " + i + ":" + receivePubKey);
< BIP47Meta.getInstance().getIdx4AddrLookup().put(receivePubKey, i);
< BIP47Meta.getInstance().getPCode4AddrLookup().put(receivePubKey, pcodeAsString);
---
> info("APIFactory", "receive from " + i + ":" + BIP47Util.getInstance(context).getReceivePubKey(pcode, i));
> BIP47Meta.getInstance().getIdx4AddrLookup().put(BIP47Util.getInstance(context).getReceivePubKey(pcode, i), i);
> BIP47Meta.getInstance().getPCode4AddrLookup().put(BIP47Util.getInstance(context).getReceivePubKey(pcode, i), pcode.toString());
1267,1268d1200
< return pcodeAsString;
<
1278a1211
> String _url = WebUtil.getAPIUrl(context);
1283c1216,1218
< StringBuilder url = new StringBuilder(BackendApiAndroid.getApiServiceUrl("tx/" + hash));
---
> StringBuilder url = new StringBuilder(_url);
> url.append("tx/");
> url.append(hash);
1322c1257
< public static synchronized boolean parseUnspentOutputs(String unspents) {
---
> private synchronized boolean parseUnspentOutputs(String unspents) {
1440c1375,1377
< public synchronized JSONObject getAddressInfo(final Pair<EnumAddressType, String> addrByType) {
---
> public synchronized JSONObject getAddressInfo(String addr) {
>
> return getXPUB(new String[] { addr }, false);
1442,1448d1378
< final ListMultimap<EnumAddressType, String> addressesByType =
< ImmutableListMultimap.<EnumAddressType, String>builder()
< .put(addrByType.first, addrByType.second)
< .build();
< return getXPUB(
< addressesByType,
< false);
1452a1383
> String _url = WebUtil.getAPIUrl(context);
1457c1388,1390
< StringBuilder url = new StringBuilder(BackendApiAndroid.getApiServiceUrl("tx/" + hash));
---
> StringBuilder url = new StringBuilder(_url);
> url.append("tx/");
> url.append(hash);
1514c1447
< private static RawFees putMock1DollarFeesEstimator() {
---
> private RawFees putMock1DollarFeesEstimator() {
1526a1460
> final String _url = WebUtil.getAPIUrl(context);
1529,1530c1463
< final String feesApiService = BackendApiAndroid.getApiServiceUrl("fees");
< response = WebUtil.getInstance(null).getURL(feesApiService + "?at=" + getAccessToken());
---
> response = WebUtil.getInstance(null).getURL(_url + "fees" + "?at=" + getAccessToken());
1538c1471
< public static RawFees parse1DollarFeesEstimator(final JSONObject payload) throws JSONException {
---
> private RawFees parse1DollarFeesEstimator(final JSONObject payload) throws JSONException {
1565c1498
< public static void parseDynamicFees_bitcoind(JSONObject payload) throws JSONException {
---
> private void parseDynamicFees_bitcoind(JSONObject payload) throws JSONException {
1695c1628
<
---
> List<String> addressStrings = new ArrayList<>();
1698a1632,1652
> if(PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUB44REG, false) == false && PrefsUtil.getInstance(context).getValue(PrefsUtil.FIRST_RUN, true)) {
> registerXPUB(HD_WalletFactory.getInstance(context).get().getAccount(0).xpubstr(), 44, null);
> }
> if(PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUB49REG, false) == false && PrefsUtil.getInstance(context).getValue(PrefsUtil.FIRST_RUN, true)) {
> registerXPUB(BIP49Util.getInstance(context).getWallet().getAccount(0).xpubstr(), 49, null);
> }
> if(PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUB84REG, false) == false && PrefsUtil.getInstance(context).getValue(PrefsUtil.FIRST_RUN, true)) {
> registerXPUB(BIP84Util.getInstance(context).getWallet().getAccount(0).xpubstr(), 84, null);
> }
> if(PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUBPREREG, false) == false && PrefsUtil.getInstance(context).getValue(PrefsUtil.FIRST_RUN, true)) {
> registerXPUB(BIP84Util.getInstance(context).getWallet().getAccount(WhirlpoolMeta.getInstance(context).getWhirlpoolPremixAccount()).xpubstr(), 84, PrefsUtil.XPUBPREREG);
> }
> if(PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUBPOSTREG, false) == false && PrefsUtil.getInstance(context).getValue(PrefsUtil.FIRST_RUN, true)) {
> registerXPUB(BIP84Util.getInstance(context).getWallet().getAccount(WhirlpoolMeta.getInstance(context).getWhirlpoolPostmix()).xpubstr(), 84, PrefsUtil.XPUBPOSTREG);
> }
> if(PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUBBADBANKREG, false) == false && PrefsUtil.getInstance(context).getValue(PrefsUtil.FIRST_RUN, true)) {
> registerXPUB(BIP84Util.getInstance(context).getWallet().getAccount(WhirlpoolMeta.getInstance(context).getWhirlpoolBadBank()).xpubstr(), 84, PrefsUtil.XPUBBADBANKLOCK);
> }
> if(PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUBRICOCHETREG, false) == false && PrefsUtil.getInstance(context).getValue(PrefsUtil.FIRST_RUN, true)) {
> registerXPUB(BIP84Util.getInstance(context).getWallet().getAccount(RicochetMeta.getInstance(context).getRicochetAccount()).zpubstr(), 84, PrefsUtil.XPUBRICOCHETREG);
> }
1702,1704c1656,1679
< final List<String> bip47Addresses = BIP47Util.getBip47Addresses(context);
< if(bip47Addresses.size() > 0) {
< s = bip47Addresses.toArray(new String[0]);
---
> addressStrings.addAll(Arrays.asList(BIP47Meta.getInstance().getIncomingAddresses(false)));
> for(String _s : Arrays.asList(BIP47Meta.getInstance().getIncomingLookAhead(context))) {
> if(!addressStrings.contains(_s)) {
> addressStrings.add(_s);
> }
> }
> for(String pcode : BIP47Meta.getInstance().getUnspentProviders()) {
> for(String addr : BIP47Meta.getInstance().getUnspentAddresses(context, pcode)) {
> if(!addressStrings.contains(addr)) {
> addressStrings.add(addr);
> }
> }
> List<Integer> idxs = BIP47Meta.getInstance().getUnspent(pcode);
> for(Integer idx : idxs) {
> String receivePubKey = BIP47Util.getInstance(context).getReceivePubKey(new PaymentCode(pcode), idx);
> BIP47Meta.getInstance().getIdx4AddrLookup().put(receivePubKey, idx);
> BIP47Meta.getInstance().getPCode4AddrLookup().put(receivePubKey, pcode.toString());
> if(!addressStrings.contains(receivePubKey)) {
> addressStrings.add(receivePubKey);
> }
> }
> }
> if(addressStrings.size() > 0) {
> s = addressStrings.toArray(new String[0]);
1709,1712c1684
< final ListMultimap<EnumAddressType, String> addressesByType = MultimapBuilder.linkedHashKeys().arrayListValues().build();
< addressesByType.put(EnumAddressType.BIP44_LEGACY, BIP49Util.getInstance(context).getWallet().getAccount(0).xpubstr());
< addressesByType.put(EnumAddressType.BIP44_LEGACY, BIP84Util.getInstance(context).getWallet().getAccount(0).xpubstr());
< addressesByType.putAll(EnumAddressType.BIP44_LEGACY, ImmutableList.copyOf(hdw.getXPUBs()));
---
> String[] all = null;
1714c1686,1690
< addressesByType.putAll(EnumAddressType.BIP44_LEGACY, ImmutableList.copyOf(s));
---
> all = new String[hdw.getXPUBs().length + 2 + s.length];
> all[0] = BIP49Util.getInstance(context).getWallet().getAccount(0).xpubstr();
> all[1] = BIP84Util.getInstance(context).getWallet().getAccount(0).xpubstr();
> System.arraycopy(hdw.getXPUBs(), 0, all, 2, hdw.getXPUBs().length);
> System.arraycopy(s, 0, all, hdw.getXPUBs().length + 2, s.length);
1716c1692,1702
< JSONObject jObj = APIFactory.getInstance(context).getXPUB(addressesByType, true);
---
> else {
> all = new String[hdw.getXPUBs().length + 2];
> all[0] = BIP49Util.getInstance(context).getWallet().getAccount(0).xpubstr();
> all[1] = BIP84Util.getInstance(context).getWallet().getAccount(0).xpubstr();
> System.arraycopy(hdw.getXPUBs(), 0, all, 2, hdw.getXPUBs().length);
> }
> JSONObject jObj = APIFactory.getInstance(context).getXPUB(all, true);
> String[] xs = new String[3];
> xs[0] = HD_WalletFactory.getInstance(context).get().getAccount(0).xpubstr();
> xs[1] = BIP49Util.getInstance(context).getWallet().getAccount(0).xpubstr();
> xs[2] = BIP84Util.getInstance(context).getWallet().getAccount(0).xpubstr();
1755,1759c1741
< final ListMultimap<EnumAddressType, String> addressesByType = ImmutableListMultimap.<EnumAddressType, String>builder()
< .putAll(EnumAddressType.BIP44_LEGACY, strPreMix, strPostMix)
< .build();
<
< final JSONObject mixMultiAddrObj = getRawXPUB(addressesByType);
---
> final JSONObject mixMultiAddrObj = getRawXPUB(new String[] { strPreMix, strPostMix });
1830c1812
< public synchronized int syncBIP47Incoming(final String[] addresses) {
---
> public synchronized int syncBIP47Incoming(String[] addresses) {
1832,1838c1814,1815
< final ListMultimap<EnumAddressType, String> addressesByType = MultimapBuilder
< .linkedHashKeys()
< .arrayListValues()
< .build();
< addressesByType.putAll(EnumAddressType.BIP44_LEGACY, ImmutableList.copyOf(addresses));
< JSONObject jsonObject = getXPUB(addressesByType, false);
< debug("APIFactory", String.format("sync BIP47 incoming:%s", jsonObject));
---
> JSONObject jsonObject = getXPUB(addresses, false);
> debug("APIFactory", "sync BIP47 incoming:" + jsonObject.toString());
1926c1903
< public synchronized int syncBIP47Outgoing(final String[] addresses) {
---
> public synchronized int syncBIP47Outgoing(String[] addresses) {
1928,1933c1905
< final ListMultimap<EnumAddressType, String> addressesByType = MultimapBuilder
< .linkedHashKeys()
< .arrayListValues()
< .build();
< addressesByType.putAll(EnumAddressType.BIP44_LEGACY, ImmutableList.copyOf(addresses));
< final JSONObject jsonObject = getXPUB(addressesByType, false);
---
> JSONObject jsonObject = getXPUB(addresses, false);
2152,2153c2124,2126
< private synchronized JSONObject getRawXPUB(
< final ListMultimap<EnumAddressType, String> addressesByType) {
---
> private synchronized JSONObject getRawXPUB(String[] xpubs) {
>
> String _url = WebUtil.getAPIUrl(context);
2166,2190c2139,2141
< final StringBuilder args = new StringBuilder();
<
< for (final EnumAddressType type : addressesByType.keySet()) {
< switch (type) {
< case BIP44_LEGACY:
< args.append("active=");
< args.append(StringUtils.join(addressesByType.get(type), URLEncoder.encode("|", "UTF-8")));
< args.append("&");
< break;
< case BIP49_SEGWIT_COMPAT:
< args.append("bip49=");
< args.append(StringUtils.join(addressesByType.get(type), URLEncoder.encode("|", "UTF-8")));
< args.append("&");
< break;
< case BIP84_SEGWIT_NATIVE:
< args.append("bip84=");
< args.append(StringUtils.join(addressesByType.get(type), URLEncoder.encode("|", "UTF-8")));
< args.append("&");
< break;
< default:
< info("APIFactory", "unknown EnumAddressType:" + type);
< break;
< }
< }
<
---
> StringBuilder args = new StringBuilder();
> args.append("active=");
> args.append(StringUtils.join(xpubs, URLEncoder.encode("|", "UTF-8")));
2198c2149,2150
< } else {
---
> }
> else {
2203,2204c2155
< final String walletApiService = BackendApiAndroid.getApiServiceUrl("wallet?");
< response = WebUtil.getInstance(context).postURL(walletApiService, args.toString());
---
> response = WebUtil.getInstance(context).postURL(_url + "wallet?", args.toString());
2206,2225c2157,2160
< } else {
<
< final Map<String,String> args = Maps.newHashMap();
< for (final EnumAddressType type : addressesByType.keySet()) {
< switch (type) {
< case BIP44_LEGACY:
< args.put("active", StringUtils.join(addressesByType.get(type), "|"));
< break;
< case BIP49_SEGWIT_COMPAT:
< args.put("bip49", StringUtils.join(addressesByType.get(type), "|"));
< break;
< case BIP84_SEGWIT_NATIVE:
< args.put("bip84", StringUtils.join(addressesByType.get(type), "|"));
< break;
< default:
< info("APIFactory", "unknown EnumAddressType:" + type);
< break;
< }
< }
<
---
> }
> else {
> HashMap<String,String> args = new HashMap<String,String>();
> args.put("active", StringUtils.join(xpubs, "|"));
2238,2239c2173
< final String walletApiService = BackendApiAndroid.getApiServiceUrl("wallet");
< response = WebUtil.getInstance(context).tor_postURL(walletApiService, args);
---
> response = WebUtil.getInstance(context).tor_postURL(_url + "wallet", args);
2607,2612c2541,2542
< final String[] s = new String[] { BIP84Util.getInstance(context).getWallet().getAccount(RicochetMeta.getInstance(context).getRicochetAccount()).xpubstr() };
<
< final ListMultimap<EnumAddressType, String> addressesByType = ImmutableListMultimap.<EnumAddressType, String>builder()
< .putAll(EnumAddressType.BIP44_LEGACY, s)
< .build();
< JSONObject jsonObject = getRawXPUB(addressesByType);
---
> String[] s = new String[] { BIP84Util.getInstance(context).getWallet().getAccount(RicochetMeta.getInstance(context).getRicochetAccount()).zpubstr() };
> JSONObject jsonObject = getRawXPUB(s);
2667c2597
< private static void onUtxoChange() {
---
> private void onUtxoChange() {
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/api/fee/EnumFeeRepresentation.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/api/fee/EnumFeeRepresentation.java
39,40c39,40
< final Integer feeForNextBlockAt10 = nonNull(rawFees.getFee(EnumFeeRate.RATE_100))
< ? rawFees.getFee(EnumFeeRate.RATE_100)
---
> final Integer feeForNextBlockAt20 = nonNull(rawFees.getFee(EnumFeeRate.RATE_200))
> ? rawFees.getFee(EnumFeeRate.RATE_200)
43c43
< if (nonNull(feeForNextBlockAt10)) {
---
> if (nonNull(feeForNextBlockAt20)) {
45c45
< suggestedFee.setDefaultPerKB(BigInteger.valueOf(feeForNextBlockAt10 * 1000L));
---
> suggestedFee.setDefaultPerKB(BigInteger.valueOf(feeForNextBlockAt20 * 1000L));
51,52c51,52
< if (isNull(rawFees.getFee(EnumFeeRate.RATE_100))) {
< rawFees.putFee(EnumFeeRate.RATE_100.getRateAsString(), feeForNextBlockAt10);
---
> if (isNull(rawFees.getFee(EnumFeeRate.RATE_200))) {
> rawFees.putFee(EnumFeeRate.RATE_200.getRateAsString(), feeForNextBlockAt20);
110,117d109
<
< public boolean is1DolFeeEstimator() {
< return this == NEXT_BLOCK_RATE;
< }
<
< public boolean isBitcoindFeeEstimator() {
< return this == BLOCK_COUNT;
< }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/bip47/BIP47Meta.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/bip47/BIP47Meta.java
5d4
< import static org.apache.commons.lang3.StringUtils.isNotBlank;
13,14d11
< import com.google.common.collect.Maps;
< import com.google.common.collect.Sets;
25d21
< import java.util.Collection;
39,41c35
< public static final String ashigaruDonationPcodeMainnet = "PM8TJUhHJzVgoxaay8njgTDdNVE8i6PuFbgsJEiKpfbX7umkVHQ9bamF1pZgEYWAmkecLt81Mcg6ybKbDW4PN41GsskGXLV89fb5ARF3ZexopEgDBs3v";
< public static final String ashigaruDonationPcodeTestnet = "PM8TJQuX14xb5VhpYUFM165WjbYHTnQvH2zdyrTJijnjYrfGM8u5tTiQ3qCFAoESb1xDnLXaqD4iqR6zFUFy3Yi1C1nN4F3hLMp7LJngjgB4gvumHnc3";
< public static final String strSamouraiDonationPCode = SamouraiWallet.getInstance().isTestNet() ? ashigaruDonationPcodeTestnet : ashigaruDonationPcodeMainnet;// public static final String strSamouraiDonationMeta = "?title=Samourai Donations&desc=Donate to help fund development of Samourai Bitcoin Wallet&user=K6tS2X8";
---
> public static final String strSamouraiDonationPCode = SamouraiWallet.samouraiDonationPCode;// public static final String strSamouraiDonationMeta = "?title=Samourai Donations&desc=Donate to help fund development of Samourai Bitcoin Wallet&user=K6tS2X8";
52d45
< private static Map<String, String> pcodeNames = null;
54d46
< private static Map<String, String> notFoundPcodeLabels = null; // useful to keep the pcode from backup on sync task
56c48
< private static Map<String, Boolean> followings = null;
---
> private static Map<String, Boolean> pcodeRoles = null;
58c50
< private static Map<String, Map<String,Integer>> pcodeUnspentIdxs = null; // unused => could be removed
---
> private static Map<String, Map<String,Integer>> pcodeUnspentIdxs = null;
67a60
> private static List<String> followingPcodes = null;
76d68
< pcodeNames = new ConcurrentHashMap<>();
78d69
< notFoundPcodeLabels = new ConcurrentHashMap<>();
80c71
< followings = new ConcurrentHashMap<>();
---
> pcodeRoles = new ConcurrentHashMap<>();
91a83
> followingPcodes = new ArrayList<>();
100d91
< pcodeNames.clear();
102d92
< notFoundPcodeLabels.clear();
104c94
< followings.clear();
---
> pcodeRoles.clear();
116,124c106
< }
<
< public void partialClearOnRestoringWallet() {
< pcodeNames.clear();
< pcodeLabels.clear();
< labelsPcode.clear();
< followings.clear();
< pcodeSegwit.clear();
< pcodeUnspentIdxs.clear();
---
> followingPcodes.clear();
129c111
< if (StringUtils.equals(label, "Ashigaru as mixing partner")) {
---
> if (StringUtils.equals(label, "Samourai as mixing partner")) {
135,138d116
< public String getName(final String pcode) {
< return pcodeNames.getOrDefault(pcode, "");
< }
<
144c122
< return "Ashigaru as mixing partner";
---
> return "Samourai as mixing partner";
153,171c131,133
< public boolean isFollowing(final String pcode) {
< return followings.getOrDefault(pcode, false);
< }
<
< public Set<String> getFollowings() {
< final Set<String> followingsFound = Sets.newHashSet();
< for (final String pcode : followings.keySet()) {
< if (isFollowing(pcode)) {
< followingsFound.add(pcode);
< }
< }
< return followingsFound;
< }
<
< synchronized public void setFollowings(final Collection<String> pcodes) {
< followings.clear();
< for (final String pcode : pcodes) {
< followings.put(pcode, true);
< }
---
> public void addFollowings(final List<String> pcodes){
> followingPcodes.clear();
> followingPcodes.addAll(pcodes);
174,175c136,137
< public void setFollowing(final String pcode, final boolean isFollowing) {
< followings.put(pcode, isFollowing);
---
> public boolean isFollowing(final String pcode){
> return followingPcodes.contains(pcode);
190,197c152
< public void setName(final String pcode, final String name) {
< pcodeNames.put(pcode, name);
< }
<
< public void setLabel(final String pcode, final String label) {
< if (StringUtils.isBlank(label) && pcodeNames.containsKey(pcode)) {
< return;
< }
---
> public void setLabel(final String pcode, final String label) {
202,203c157,158
< public void putNotFoundPcodes(final String pcode, final String label) {
< notFoundPcodeLabels.put(pcode, label);
---
> public void setRole (final String pcode, final boolean isFollowing) {
> pcodeRoles.put(pcode, isFollowing);
206c161
< public Set<String> getPcodes() {
---
> public Set<String> getLabels() {
210,213d164
< public Map<String, String> getCopyOfPcodeLabels() {
< return Maps.newHashMap(pcodeLabels);
< }
<
240c191
< final int outgoingStatus = getOutgoingStatus(key);
---
> final int outgoingStatus = BIP47Meta.getInstance().getOutgoingStatus(key);
242c193
< && (!confirmed || outgoingStatus == BIP47Meta.STATUS_SENT_CFM)) {
---
> && outgoingStatus == BIP47Meta.STATUS_SENT_CFM) {
285c236,241
< return pcodeArchived.getOrDefault(pcode, false);
---
> if(!pcodeArchived.containsKey(pcode)) {
> pcodeArchived.put(pcode, false);
> return false;
> } else {
> return pcodeArchived.get(pcode);
> }
305c261,270
<
---
> /*
> public void incIncomingIdx(String pcode) {
> if(!pcodeIncomingIdxs.containsKey(pcode)) {
> pcodeIncomingIdxs.put(pcode, 1);
> }
> else {
> pcodeIncomingIdxs.put(pcode, pcodeIncomingIdxs.get(pcode) + 1);
> }
> }
> */
343,344c308
< if(!includeArchived && getArchived(pcode)) continue;
< if(isNull(pcodeUnspentIdxs.get(pcode))) continue;
---
> if(!includeArchived && nonNull(pcodeArchived.get(pcode))) continue;
424,430d387
< public boolean isOutgoingStatusSent(final String pcode) {
< final Pair<String, Integer> txAndStatus = pcodeOutgoingStatus.get(pcode);
< if (isNull(txAndStatus)) return false;
< return txAndStatus.getValue() == STATUS_SENT_CFM ||
< txAndStatus.getValue() == STATUS_SENT_NO_CFM;
< }
<
443,451c400,408
<
< for(final Map.Entry<String, Pair<String, Integer>> pcodeToTxInfo : pcodeOutgoingStatus.entrySet()) {
< final Pair<String, Integer> txInfo = pcodeToTxInfo.getValue();
< final Integer confirmedStatus = nonNull(txInfo.getRight()) ? txInfo.getRight() : STATUS_NOT_SENT;
< final String txHash = txInfo.getLeft();
< if (confirmedStatus == STATUS_SENT_NO_CFM && isNotBlank(txHash)) {
< final String pcode = pcodeToTxInfo.getKey();
< ret.add(Pair.of(pcode, txHash));
< }
---
> // info("BIP47Meta", "key set:" + pcodeOutgoingStatus.keySet().size());
> for(final String pcode : pcodeOutgoingStatus.keySet()) {
> // info("BIP47Meta", "pcode:" + pcode.toString());
> // info("BIP47Meta", "tx:" + pcodeOutgoingStatus.get(pcode).getLeft());
> // info("BIP47Meta", "status:" + pcodeOutgoingStatus.get(pcode).getRight());
> // if(pcodeOutgoingStatus.get(pcode).getRight() != STATUS_SENT_CFM && pcodeOutgoingStatus.get(pcode).getLeft() != null && pcodeOutgoingStatus.get(pcode).getLeft().length() > 0) {
> // ret.add(Pair.of(pcode, pcodeOutgoingStatus.get(pcode).getLeft()));
> // }
> ret.add(Pair.of(pcode, pcodeOutgoingStatus.get(pcode).getLeft()));
529,530c486
< synchronized public void remove(final String pcode) {
< pcodeNames.remove(pcode);
---
> synchronized public void remove(final String pcode) {
533,534c489
< notFoundPcodeLabels.remove(pcode);
< followings.remove(pcode);
---
> pcodeRoles.remove(pcode);
569c524
< for(final String pcode : getPcodes()) {
---
> for(final String pcode : getLabels()) {
608d562
< pobj.put("name", pcodeNames.get(pcode));
612c566
< pobj.put("following", followings.get(pcode));
---
> pobj.put("following", pcodeRoles.get(pcode));
646c600,601
< } else {
---
> }
> else {
669,677d623
< final JSONArray notFoundPcodes = new JSONArray();
< for (final Map.Entry<String, String> pcodeLabel : notFoundPcodeLabels.entrySet()) {
< final JSONObject pobj = new JSONObject();
< pobj.put("payment_code", pcodeLabel.getKey());
< pobj.put("label", pcodeLabel.getValue());
< notFoundPcodes.put(pobj);
< }
< jsonPayload.put("not_found_pcodes", notFoundPcodes);
<
699,701c645,648
< final JSONArray pcodes = jsonPayload.has("pcodes")
< ? jsonPayload.getJSONArray("pcodes")
< : new JSONArray();
---
> JSONArray pcodes = new JSONArray();
> if(jsonPayload.has("pcodes")) {
> pcodes = jsonPayload.getJSONArray("pcodes");
> }
711,718c658,659
< if (obj.has("name")) {
< pcodeNames.put(paymentCode, obj.getString("name"));
< } else {
< pcodeNames.put(paymentCode, label); // to manage old version
< }
< if (obj.has("following")) {
< followings.put(paymentCode, obj.getBoolean("following"));
< }
---
> if (obj.has("following"))
> pcodeRoles.put(paymentCode, obj.getBoolean("following"));
772,782d712
< }
<
< final JSONArray notFoundPcodes = jsonPayload.has("not_found_pcodes")
< ? jsonPayload.getJSONArray("not_found_pcodes")
< : new JSONArray();
<
< for(int i = 0; i < notFoundPcodes.length(); i++) {
< final JSONObject obj = notFoundPcodes.getJSONObject(i);
< final String paymentCode = obj.getString("payment_code");
< final String label = obj.getString("label");
< notFoundPcodeLabels.put(paymentCode, label);
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/bip47/BIP47Util.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/bip47/BIP47Util.java
3,6d2
< import static com.samourai.wallet.bip47.BIP47Meta.STATUS_SENT_CFM;
< import static org.apache.commons.lang3.StringUtils.isBlank;
< import static java.util.Objects.nonNull;
<
10d5
< import android.util.Log;
13,17d7
< import androidx.annotation.NonNull;
< import androidx.core.content.ContextCompat;
< import androidx.lifecycle.LiveData;
< import androidx.lifecycle.MutableLiveData;
<
20d9
< import com.samourai.wallet.api.backend.beans.HttpException;
30d18
< import com.samourai.wallet.util.tech.ThreadHelper;
35a24
> import org.jetbrains.annotations.Nullable;
41,43d29
< import java.util.ArrayList;
< import java.util.Arrays;
< import java.util.List;
44a31,33
> import androidx.core.content.ContextCompat;
> import androidx.lifecycle.LiveData;
> import androidx.lifecycle.MutableLiveData;
52,54c41,42
< public class BIP47Util extends BIP47UtilGeneric {
<
< public static final String TAG = "BIP47Util";
---
> import static com.samourai.wallet.bip47.BIP47Meta.STATUS_SENT_CFM;
> import static org.apache.commons.lang3.StringUtils.isBlank;
56c44
< private static final boolean ALWAYS_ACCEPT_SEGWIT = true;
---
> public class BIP47Util extends BIP47UtilGeneric {
90c78
< private static NetworkParameters getNetworkParams() {
---
> private NetworkParameters getNetworkParams() {
152,154c140,141
< public void setAvatar(final Bitmap bitmap) {
< paynymLogo.postValue(null); // reset in order to ensure the push with the next post
< if (nonNull(bitmap)) {
---
> public void setAvatar(@Nullable Bitmap bitmap) {
> if (bitmap != null) {
156,157d142
< } else {
< Log.d(TAG, "bitmap is null in setAvatar()");
168c153,167
< loadBotImage(finalUrl, 3);
---
> Request.Builder rb = new Request.Builder().url(finalUrl);
> OkHttpClient.Builder builder = com.samourai.wallet.util.network.WebUtil.getInstance(context).httpClientBuilder(finalUrl);
> OkHttpClient client = builder.build();
> Response response = client.newCall(rb.build()).execute();
> if (response.isSuccessful()) {
> File file = avatarImage();
> if (!file.exists()) {
> file.createNewFile();
> }
> byte[] stream = response.body().bytes();
> OutputStream outStream = new FileOutputStream(file);
> outStream.write(stream);
> Bitmap bitmap = BitmapFactory.decodeFile(file.getPath());
> setAvatar(bitmap);
> }
174,215c173
< private void loadBotImage(final String finalUrl, final int maxRetry)
< throws HttpException, IOException {
<
< final Request.Builder rb = new Request.Builder().url(finalUrl);
< final OkHttpClient client = com.samourai.wallet.util.network.WebUtil
< .getInstance(context)
< .httpClientBuilder(finalUrl)
< .build();
< final Response response = client.newCall(rb.build()).execute();
< if (response.isSuccessful()) {
<
< final File file = avatarImage();
< if (!file.exists()) {
< file.createNewFile();
< }
<
< boolean status = true;
< try (final OutputStream outStream = new FileOutputStream(file)) {
< outStream.write(response.body().bytes());
< } catch (final Exception e) {
< Log.e(TAG, "issue on creating paynym bitmap");
< status = false;
< }
<
< if (status) {
< final Bitmap bitmap = BitmapFactory.decodeFile(file.getPath());
< if (nonNull(bitmap)) {
< setAvatar(bitmap);
< return;
< }
< }
< }
<
< if (maxRetry > 0) {
< ThreadHelper.pauseMillis(5_000L);
< loadBotImage(finalUrl, maxRetry-1);
< } else {
< Log.e(TAG, "loading bot image failed");
< }
< }
<
< synchronized public String getSendAddressString(
---
> synchronized public String getDestinationAddrFromPcode(
219c177
< return getSendAddressString(pcodeAsString, 0);
---
> return getDestinationAddrFromPcode(pcodeAsString, 0);
223c181
< synchronized public String getSendAddressString(
---
> synchronized public String getDestinationAddrFromPcode(
236c194
< if (ALWAYS_ACCEPT_SEGWIT || BIP47Meta.getInstance().getSegwit(pcodeAsString)) {
---
> if (BIP47Meta.getInstance().getSegwit(pcodeAsString)) {
239c197
< getNetworkParams()).getBech32AsString();
---
> SamouraiWallet.getInstance().getCurrentNetworkParams()).getBech32AsString();
243c201
< .toAddress(getNetworkParams()).toString();
---
> .toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
258a217,228
> public String getSendAddressString(final String pcode) throws Exception {
> final PaymentAddress paymentAddress = getPaymentAddressSend(pcode, 0);
> if (BIP47Meta.getInstance().getSegwit(pcode)) {
> return new SegwitAddress(paymentAddress.getSendECKey(), getNetworkParams())
> .getBech32AsString();
> } else {
> return paymentAddress.getSendECKey().toAddress(getNetworkParams()).toString();
> }
> }
>
>
>
280,307d249
< }
<
< @NonNull
< public static List<String> getBip47Addresses(final Context context) throws Exception {
< final List<String> addressStrings = new ArrayList<>();
< addressStrings.addAll(Arrays.asList(BIP47Meta.getInstance().getIncomingAddresses(false)));
< for(String _s : Arrays.asList(BIP47Meta.getInstance().getIncomingLookAhead(context))) {
< if(!addressStrings.contains(_s)) {
< addressStrings.add(_s);
< }
< }
< for(String pcode : BIP47Meta.getInstance().getUnspentProviders()) {
< for(String addr : BIP47Meta.getInstance().getUnspentAddresses(context, pcode)) {
< if(!addressStrings.contains(addr)) {
< addressStrings.add(addr);
< }
< }
< List<Integer> idxs = BIP47Meta.getInstance().getUnspent(pcode);
< for(Integer idx : idxs) {
< String receivePubKey = BIP47Util.getInstance(context).getReceivePubKey(new PaymentCode(pcode), idx);
< BIP47Meta.getInstance().getIdx4AddrLookup().put(receivePubKey, idx);
< BIP47Meta.getInstance().getPCode4AddrLookup().put(receivePubKey, pcode.toString());
< if(!addressStrings.contains(receivePubKey)) {
< addressStrings.add(receivePubKey);
< }
< }
< }
< return addressStrings;
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/bip47/paynym/WebUtil.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/bip47/paynym/WebUtil.java
5,6d4
< import com.samourai.wallet.paynym.api.PayNymApiService;
<
15c13
< public static final String PAYNYM_API = PayNymApiService.PAYNYM_API;
---
> public static final String PAYNYM_API = "https://paynym.is/";
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/bip47/SendNotifTxFactory.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/bip47/SendNotifTxFactory.java
17,18c17,18
< public String SAMOURAI_NOTIF_TX_FEE_ADDRESS = "bc1qca73k4dt9sfr47rr3wvpmpl08xs5f7tvhsxhdt";
< public String TESTNET_SAMOURAI_NOTIF_TX_FEE_ADDRESS = "tb1qe2s3cre37j2ajlrk0gpdkymujqxs7zt47htwm7";
---
> public String SAMOURAI_NOTIF_TX_FEE_ADDRESS = "bc1qncfysagz0072a894kvzyxqwpvj5ckfj5kctmtk";
> public String TESTNET_SAMOURAI_NOTIF_TX_FEE_ADDRESS = "tb1qh287jqsh6mkpqmd8euumyfam00fkr78qhrdnde";
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/collaborate/CollaborateActivity.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/collaborate/CollaborateActivity.kt
76,77d75
< getWindow().statusBarColor = resources.getColor(R.color.grey_accent)
< getWindow().navigationBarColor = resources.getColor(R.color.window)
508a507
> var url by remember { mutableStateOf("${WebUtil.PAYNYM_API}${pcode}/avatar") }
509a509,511
> LaunchedEffect(pcode) {
> url = "${WebUtil.PAYNYM_API}${pcode}/avatar"
> }
517c519
< pcode = pcode,
---
> url = url,
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/collaborate/ParticipateSegment.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/collaborate/ParticipateSegment.kt
249a250,251
> val url = "${WebUtil.PAYNYM_API}${sorobanRequest!!.sender.toString()}/avatar"
>
267c269
< pcode = sorobanRequest!!.sender.toString(),
---
> url = url,
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/collaborate/Paynym.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/collaborate/Paynym.kt
11,19c11
< import androidx.compose.foundation.layout.Arrangement
< import androidx.compose.foundation.layout.Box
< import androidx.compose.foundation.layout.Column
< import androidx.compose.foundation.layout.Row
< import androidx.compose.foundation.layout.fillMaxWidth
< import androidx.compose.foundation.layout.height
< import androidx.compose.foundation.layout.padding
< import androidx.compose.foundation.layout.requiredHeight
< import androidx.compose.foundation.layout.size
---
> import androidx.compose.foundation.layout.*
27,38c19
< import androidx.compose.material.Divider
< import androidx.compose.material.ExperimentalMaterialApi
< import androidx.compose.material.Icon
< import androidx.compose.material.IconButton
< import androidx.compose.material.LinearProgressIndicator
< import androidx.compose.material.ModalBottomSheetState
< import androidx.compose.material.ModalBottomSheetValue
< import androidx.compose.material.Scaffold
< import androidx.compose.material.Text
< import androidx.compose.material.TextField
< import androidx.compose.material.TextFieldDefaults
< import androidx.compose.material.TopAppBar
---
> import androidx.compose.material.*
42,44c23
< import androidx.compose.runtime.Composable
< import androidx.compose.runtime.LaunchedEffect
< import androidx.compose.runtime.getValue
---
> import androidx.compose.runtime.*
46,49d24
< import androidx.compose.runtime.mutableStateOf
< import androidx.compose.runtime.remember
< import androidx.compose.runtime.rememberCoroutineScope
< import androidx.compose.runtime.setValue
70a46
> import com.samourai.wallet.bip47.paynym.WebUtil
75d50
< import com.samourai.wallet.paynym.api.PayNymApiService
100d74
< val spendable by collaborateViewModel.spendable.observeAsState(initial = listOf())
105,111c79
< var paynyms = arrayListOf<String>().apply {
< if (paynymChooserType == PaynymChooserType.SPEND) {
< addAll(spendable)
< } else {
< addAll(following)
< }
< }
---
> var paynyms = arrayListOf<String>().apply { addAll(following) }
112a81,86
> if (cahootType?.cahootsMode == CahootsMode.SOROBAN && cahootType?.cahootsType != CahootsType.STOWAWAY) {
> paynyms = arrayListOf<String>().apply {
> add(BIP47Meta.getMixingPartnerCode())
> addAll(following)
> }
> }
122c96
< addAll(paynyms.filter {
---
> addAll(following.filter {
164c138
< collaborateViewModel.applySearch(it, paynymChooserType)
---
> collaborateViewModel.applySearch(it)
168c142
< collaborateViewModel.applySearch(null, paynymChooserType)
---
> collaborateViewModel.applySearch(null)
200c174
< if (paynymChooserType == PaynymChooserType.COLLABORATE && it == BIP47Meta.getMixingPartnerCode()) {
---
> if (it == BIP47Meta.getMixingPartnerCode()) {
214c188
< PaynymAvatar(pcode = it, nym = "${BIP47Meta.getInstance().getDisplayLabel(it)} ${if(connected) "(connected)" else ""}",
---
> PaynymAvatar(pcode = it, nym = "${BIP47Meta.getInstance().getLabel(it)} ${if(connected) "(connected)" else ""}",
296a271,272
> val url = "${WebUtil.PAYNYM_API}${pcode}/avatar"
>
315c291
< pcode = pcode,
---
> url = url,
342,343c318
< pcode: String,
< modifier: Modifier = Modifier,
---
> url: String, modifier: Modifier = Modifier,
349c324
< LaunchedEffect(pcode) {
---
> LaunchedEffect(url) {
352c327
< .load("${PayNymApiService.PAYNYM_API}${pcode}/avatar")
---
> .load(url)
362,378d336
< scope.launch {
< Picasso.get()
< .load("${PayNymApiService.PAYNYM_API}preview/${pcode}")
< .into(object : Target {
< override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?) {
< if (bitmap != null) {
< imageBitMap = bitmap.asImageBitmap();
< }
< }
<
< override fun onBitmapFailed(e: Exception?, errorDrawable: Drawable?) {
< }
<
< override fun onPrepareLoad(placeHolderDrawable: Drawable?) {
< }
< })
< }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/collaborate/TransactionSetup.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/collaborate/TransactionSetup.kt
3,10c3
< import androidx.compose.animation.AnimatedContent
< import androidx.compose.animation.ExperimentalAnimationApi
< import androidx.compose.animation.SizeTransform
< import androidx.compose.animation.fadeIn
< import androidx.compose.animation.fadeOut
< import androidx.compose.animation.slideInVertically
< import androidx.compose.animation.slideOutVertically
< import androidx.compose.animation.with
---
> import androidx.compose.animation.*
13,23c6
< import androidx.compose.foundation.layout.Arrangement
< import androidx.compose.foundation.layout.Box
< import androidx.compose.foundation.layout.BoxWithConstraints
< import androidx.compose.foundation.layout.Column
< import androidx.compose.foundation.layout.PaddingValues
< import androidx.compose.foundation.layout.Row
< import androidx.compose.foundation.layout.fillMaxHeight
< import androidx.compose.foundation.layout.fillMaxWidth
< import androidx.compose.foundation.layout.padding
< import androidx.compose.foundation.layout.requiredHeight
< import androidx.compose.foundation.layout.size
---
> import androidx.compose.foundation.layout.*
29,44c12
< import androidx.compose.material.Button
< import androidx.compose.material.ButtonDefaults
< import androidx.compose.material.ExperimentalMaterialApi
< import androidx.compose.material.Icon
< import androidx.compose.material.IconButton
< import androidx.compose.material.ListItem
< import androidx.compose.material.MaterialTheme
< import androidx.compose.material.Scaffold
< import androidx.compose.material.Slider
< import androidx.compose.material.SliderDefaults
< import androidx.compose.material.Surface
< import androidx.compose.material.Text
< import androidx.compose.material.TextButton
< import androidx.compose.material.TextField
< import androidx.compose.material.TextFieldDefaults
< import androidx.compose.material.TopAppBar
---
> import androidx.compose.material.*
48,50c16
< import androidx.compose.runtime.Composable
< import androidx.compose.runtime.LaunchedEffect
< import androidx.compose.runtime.getValue
---
> import androidx.compose.runtime.*
52,55d17
< import androidx.compose.runtime.mutableStateOf
< import androidx.compose.runtime.remember
< import androidx.compose.runtime.rememberCoroutineScope
< import androidx.compose.runtime.setValue
71,76c33
< import androidx.compose.ui.text.input.ImeAction
< import androidx.compose.ui.text.input.KeyboardType
< import androidx.compose.ui.text.input.OffsetMapping
< import androidx.compose.ui.text.input.TextFieldValue
< import androidx.compose.ui.text.input.TransformedText
< import androidx.compose.ui.text.input.VisualTransformation
---
> import androidx.compose.ui.text.input.*
92,99c49
< import com.samourai.wallet.theme.samouraiAccent
< import com.samourai.wallet.theme.samouraiBottomSheetBackground
< import com.samourai.wallet.theme.samouraiError
< import com.samourai.wallet.theme.samouraiSurface
< import com.samourai.wallet.theme.samouraiTextFieldBg
< import com.samourai.wallet.theme.samouraiTextPrimary
< import com.samourai.wallet.theme.samouraiTextSecondary
< import com.samourai.wallet.theme.samouraiWindow
---
> import com.samourai.wallet.theme.*
108c58
< import java.util.Locale
---
> import java.util.*
198c148
< Icon(painter = painterResource(id = R.drawable.qrcode_scan), contentDescription = "")
---
> Icon(painter = painterResource(id = R.drawable.ic_crop_free_white_24dp), contentDescription = "")
259c209
< text = stringResource(id = R.string.estimated_confirmation_time),
---
> text = stringResource(id = R.string.estimated_wait_time),
689c639
< pcode = pcode!!
---
> url = "${WebUtil.PAYNYM_API}${pcode}/avatar"
766,769c716
< val feeRange by vm.getFeeRange().observeAsState()
< vm.setFeeRange(feeRange!!)
< val feeSliderValue by vm.feeSliderValue.observeAsState(feeRange!!)
<
---
> val feeSliderValue by vm.feeSliderValue.observeAsState(0.5f)
845c792
< Text(text = "sat/vB ")
---
> Text(text = "sat/b ")
874c821
< text = "$satsPerByte sat/vB",
---
> text = "$satsPerByte sat/b",
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/collaborate/viewmodels/CahootsTransactionViewModel.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/collaborate/viewmodels/CahootsTransactionViewModel.kt
18d17
< import com.samourai.wallet.send.review.ReviewTxModel.findTransactionPriority
221,224d219
< fun getFeeRange() : LiveData<Float> {
< return feeRange
< }
<
226,228d220
<
< FeeUtil.getInstance().normalize()
<
232,233c224,226
<
<
---
> if (feeHigh == 1000L && feeLow == 1000L) {
> feeHigh = 3000L
> }
239,269c232,242
< if (FeeUtil.getInstance().feeRepresentation.is1DolFeeEstimator) {
<
< var transactionPriority = findTransactionPriority(fees.toLong(), feeHigh, feeLow)
< var priorityDesc = transactionPriority!!.getDescription(
< FeeUtil.getInstance().feeRepresentation,
< fees.toLong(),
< feeLow,
< feeMed,
< feeHigh
< )
< estBlocks.postValue(priorityDesc)
< } else {
< //Calculate Block confirm estimation
< val pct: Double
< var nbBlocks = 6
< if (fees <= feeLow.toDouble()) {
< pct = feeLow.toDouble() / fees
< nbBlocks = ceil(pct * 24.0).toInt()
< } else if (fees >= feeHigh.toDouble()) {
< pct = feeHigh.toDouble() / fees
< nbBlocks = ceil(pct * 2.0).toInt()
< if (nbBlocks < 1) {
< nbBlocks = 1
< }
< } else {
< pct = feeMed.toDouble() / fees
< nbBlocks = ceil(pct * 6.0).toInt()
< }
< var strBlocks = "$nbBlocks blocks"
< if (nbBlocks > 50) {
< strBlocks = "50+ blocks"
---
> //Calculate Block confirm estimation
> val pct: Double
> var nbBlocks = 6
> if (fees <= feeLow.toDouble()) {
> pct = feeLow.toDouble() / fees
> nbBlocks = ceil(pct * 24.0).toInt()
> } else if (fees >= feeHigh.toDouble()) {
> pct = feeHigh.toDouble() / fees
> nbBlocks = ceil(pct * 2.0).toInt()
> if (nbBlocks < 1) {
> nbBlocks = 1
271c244,250
< estBlocks.postValue(strBlocks)
---
> } else {
> pct = feeMed.toDouble() / fees
> nbBlocks = ceil(pct * 6.0).toInt()
> }
> var strBlocks = "$nbBlocks blocks"
> if (nbBlocks > 50) {
> strBlocks = "50+ blocks"
272a252
> estBlocks.postValue(strBlocks)
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/collaborate/viewmodels/CollaborateViewModel.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/collaborate/viewmodels/CollaborateViewModel.kt
15d14
< import com.samourai.wallet.collaborate.PaynymChooserType
40d38
< private var spendableList = ArrayList<String>()
42d39
< private var spendableListLive = MutableLiveData<ArrayList<String>>()
50c47
< private var sorobanListenJob: Job? = null
---
> private var sorobanListenJob: Job? = null;
55,57d51
< val spendable: LiveData<ArrayList<String>>
< get() = spendableListLive
<
80,83c74
< try {
< sorobanWalletCounterparty =
< androidSorobanWalletService.sorobanWalletCounterparty;
< } catch (_: Exception) {}
---
> sorobanWalletCounterparty = androidSorobanWalletService.sorobanWalletCounterparty;
106d96
< BIP47Meta.getInstance().setName(paynym.code, paynym.nymName)
112c102
< BIP47Meta.getInstance().setFollowings(followings)
---
> BIP47Meta.getInstance().addFollowings(followings)
131,132d120
< spendableList = ArrayList(BIP47Meta.getInstance().getSortedByLabels(false))
< spendableListLive.postValue(ArrayList(spendableList))
151,173c139,148
< fun applySearch(query: String?, paynymChooserType: PaynymChooserType) {
< if (paynymChooserType == PaynymChooserType.SPEND) {
< if (query == null) {
< spendableListLive.postValue(spendableList);
< return
< }
< viewModelScope.launch {
< val items = spendableList.filter {
< BIP47Meta.getInstance().getDisplayLabel(it).lowercase().indexOf(query.lowercase()) != -1
< }.toList()
< spendableListLive.postValue(ArrayList(items))
< }
< } else {
< if (query == null) {
< followingListLive.postValue(followingList);
< return
< }
< viewModelScope.launch {
< val items = followingList.filter {
< BIP47Meta.getInstance().getDisplayLabel(it).lowercase().indexOf(query.lowercase()) != -1
< }.toList()
< followingListLive.postValue(ArrayList(items))
< }
---
> fun applySearch(query: String?) {
> if (query == null) {
> followingListLive.postValue(followingList);
> return
> }
> viewModelScope.launch {
> val items = followingList.filter {
> BIP47Meta.getInstance().getDisplayLabel(it).lowercase().indexOf(query.lowercase()) != -1
> }.toList()
> followingListLive.postValue(ArrayList(items))
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/CreateWalletActivity.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/CreateWalletActivity.java
75,76c75
< getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.networking));
< getWindow().setNavigationBarColor(ContextCompat.getColor(this, R.color.networking));
---
> getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.window));
412c411
< PrefsUtil.getInstance(CreateWalletActivity.this).setValue(PrefsUtil.WALLET_SCAN_COMPLETE, false);
---
> PrefsUtil.getInstance(CreateWalletActivity.this).setValue(PrefsUtil.FIRST_RUN, true);
415c414
< PrefsUtil.getInstance(CreateWalletActivity.this).setValue(PrefsUtil.WALLET_SCAN_COMPLETE, false);
---
> PrefsUtil.getInstance(CreateWalletActivity.this).setValue(PrefsUtil.FIRST_RUN, true);
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/explorer/ExplorerActivity.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/explorer/ExplorerActivity.kt
24d23
< import com.samourai.wallet.util.PrefsUtil
26d24
< import com.samourai.wallet.util.network.WebUtil
138,140c136
< val blockExplorerURL = PrefsUtil.getInstance(applicationContext).getValue(PrefsUtil.BLOCK_EXPLORER_URL, "") + "/tx/"
<
< var url = "$blockExplorerURL${txId}"
---
> var url = "$blockExplorer${txId}"
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/fragments/PaynymSelectModalFragment.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/fragments/PaynymSelectModalFragment.kt
28d27
< import com.squareup.picasso.Callback
44a44,45
> private val TAG = "TxAnimUIActivity"
>
148c149
< throw NetworkErrorException("paynym.rs error");
---
> throw NetworkErrorException("paynym.is error");
152c153
< Toast.makeText(activity, "Network error while loading from paynym.rs", Toast.LENGTH_LONG).show()
---
> Toast.makeText(activity, "Network error while loading from paynym.is", Toast.LENGTH_LONG).show()
249,251c250,252
< if (code != null) {
< setPayNymLogos(code, holder.avatar)
< }
---
> Picasso.get()
> .load("${WebUtil.PAYNYM_API}${code}/avatar")
> .into(holder.avatar)
260,262d260
<
< private val TAG = "PaynymSelectModalFrag"
<
272,339d269
< }
<
< fun setPayNymLogos(strPaymentCode: String, avatar: ImageView) {
< try {
< Picasso.get().load(WebUtil.PAYNYM_API + strPaymentCode + "/avatar")
< .into(avatar, createPicassoCallback(strPaymentCode, avatar))
< } catch (t: Throwable) {
< /**
< * This catch block is useful if ever the onSuccess/onError callback system
< * throws a runtime exception.
< * It indicates a problem to be fixed, so we log in error.
< * This has already been the case through the method LogUtil#error.
< */
< Log.e(
< TAG,
< String.format(
< "Throwable with Picasso on /avatar %s : %s",
< strPaymentCode,
< t.message
< ),
< t
< )
< avatar.setImageResource(R.drawable.paynym)
< }
< }
<
< private fun createPicassoCallback(
< strPaymentCode: String,
< avatar: ImageView
< ): Callback {
< return object : Callback {
< override fun onSuccess() {
< }
<
< override fun onError(e: java.lang.Exception) {
< try {
< Picasso.get().load(WebUtil.PAYNYM_API + "preview/" + strPaymentCode)
< .into(avatar, object : Callback {
< override fun onSuccess() {}
<
< override fun onError(e: java.lang.Exception) {
< Log.e(
< TAG,
< "issue when loading avatar for $strPaymentCode", e
< )
< avatar.setImageResource(R.drawable.paynym)
< }
< })
< } catch (t: Throwable) {
< /**
< * This catch block is useful if ever the onSuccess/onError callback system
< * throws a runtime exception.
< * It indicates a problem to be fixed, so we log in error.
< * This has already been the case through the method LogUtil#error.
< */
< Log.e(
< TAG,
< String.format(
< "Throwable with Picasso on /preview %s : %s",
< strPaymentCode,
< t.message
< ),
< t
< )
< avatar.setImageResource(R.drawable.paynym)
< }
< }
< }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/home/AccountSelectionActivity.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/home/AccountSelectionActivity.kt
53c53,54
< import com.samourai.wallet.theme.samouraiBoxHeaderBackgroundBlack
---
> import com.samourai.wallet.theme.samouraiPostmixSpendBlueButton
> import com.samourai.wallet.theme.samouraiWindow
68,70c69
< window.statusBarColor = resources.getColor(R.color.networking)
< window.navigationBarColor = resources.getColor(R.color.networking)
<
---
> window.statusBarColor = resources.getColor(R.color.samouraiWindow)
72,73c71
< window.statusBarColor = getColor(R.color.networking)
< window.navigationBarColor = resources.getColor(R.color.networking)
---
> window.statusBarColor = getColor(R.color.samouraiWindow)
76,80d73
< val isLoadingWallet = AppUtil.getInstance(applicationContext).walletLoading.value
< accountSelectionModel.setLoading(isLoadingWallet ?:false)
< if ((isLoadingWallet != null) && !isLoadingWallet) {
< updateBalanceValues()
< }
84c77,78
< updateBalanceValues()
---
> accountSelectionModel.setDepositBalance(BalanceUtil.getBalance(SamouraiAccountIndex.DEPOSIT, this));
> accountSelectionModel.setPostmixBalance(BalanceUtil.getBalance(SamouraiAccountIndex.POSTMIX, this));
92,106d85
<
< private fun updateBalanceValues() {
< accountSelectionModel.setDepositBalance(
< BalanceUtil.getBalance(
< SamouraiAccountIndex.DEPOSIT,
< this
< )
< )
< accountSelectionModel.setPostmixBalance(
< BalanceUtil.getBalance(
< SamouraiAccountIndex.POSTMIX,
< this
< )
< )
< }
122,123c101,102
< Triple(SamouraiAccountIndex.DEPOSIT, R.drawable.ic_deposit_account, Color(71, 77, 89)),
< Triple(SamouraiAccountIndex.POSTMIX, R.drawable.ic_postmix_account, Color(37, 65, 123)))
---
> Triple(SamouraiAccountIndex.DEPOSIT, R.drawable.ic_deposit_account, Color(110, 118, 137)),
> Triple(SamouraiAccountIndex.POSTMIX, R.drawable.ic_postmix_account, samouraiPostmixSpendBlueButton))
131c110
< color = samouraiBoxHeaderBackgroundBlack
---
> color = samouraiWindow
217,219d195
< )
< intent.putExtra("isDonation",
< currentIntent.getBooleanExtra("isDonation", false)
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/home/BalanceActivity.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/home/BalanceActivity.kt
1,1479c1,1356
< package com.samourai.wallet.home
<
< import android.content.BroadcastReceiver
< import android.content.ClipData
< import android.content.ClipboardManager
< import android.content.Context
< import android.content.DialogInterface
< import android.content.Intent
< import android.content.IntentFilter
< import android.content.pm.ActivityInfo
< import android.graphics.BitmapFactory
< import android.graphics.Typeface
< import android.graphics.drawable.BitmapDrawable
< import android.net.Uri
< import android.os.AsyncTask
< import android.os.Bundle
< import android.os.Handler
< import android.util.Log
< import android.util.TypedValue
< import android.view.Menu
< import android.view.MenuItem
< import android.view.View
< import android.widget.EditText
< import android.widget.ImageView
< import android.widget.LinearLayout
< import android.widget.TextView
< import android.widget.Toast
< import androidx.activity.result.contract.ActivityResultContracts
< import androidx.activity.viewModels
< import androidx.appcompat.app.AlertDialog
< import androidx.core.content.ContextCompat
< import androidx.core.view.isVisible
< import androidx.lifecycle.viewModelScope
< import androidx.localbroadcastmanager.content.LocalBroadcastManager
< import androidx.recyclerview.widget.LinearLayoutManager
< import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
< import androidx.transition.ChangeBounds
< import androidx.transition.TransitionManager
< import com.dm.zbar.android.scanner.ZBarConstants
< import com.google.android.material.dialog.MaterialAlertDialogBuilder
< import com.google.android.material.shape.ShapeAppearanceModel
< import com.google.common.collect.Lists
< import com.google.gson.Gson
< import com.samourai.wallet.R
< import com.samourai.wallet.ReceiveActivity
< import com.samourai.wallet.SamouraiActivity
< import com.samourai.wallet.SamouraiWallet
< import com.samourai.wallet.access.AccessFactory
< import com.samourai.wallet.api.APIFactory
< import com.samourai.wallet.api.APIFactory.TxMostRecentDateComparator
< import com.samourai.wallet.api.Tx
< import com.samourai.wallet.bip47.BIP47Meta
< import com.samourai.wallet.bip47.BIP47Util
< import com.samourai.wallet.bip47.paynym.WebUtil
< import com.samourai.wallet.cahoots.Cahoots
< import com.samourai.wallet.cahoots.psbt.PSBTUtil
< import com.samourai.wallet.collaborate.CollaborateActivity
< import com.samourai.wallet.constants.SamouraiAccountIndex.DEPOSIT
< import com.samourai.wallet.constants.SamouraiAccountIndex.POSTMIX
< import com.samourai.wallet.crypto.AESUtil
< import com.samourai.wallet.crypto.DecryptionException
< import com.samourai.wallet.databinding.ActivityBalanceBinding
< import com.samourai.wallet.fragments.CameraFragmentBottomSheet
< import com.samourai.wallet.fragments.ScanFragment
< import com.samourai.wallet.hd.HD_WalletFactory
< import com.samourai.wallet.home.adapters.TxAdapter
< import com.samourai.wallet.network.NetworkDashboard
< import com.samourai.wallet.network.dojo.DojoUtil
< import com.samourai.wallet.pairing.PairingMenuActivity
< import com.samourai.wallet.payload.ExternalBackupManager.askPermission
< import com.samourai.wallet.payload.ExternalBackupManager.hasPermissions
< import com.samourai.wallet.payload.ExternalBackupManager.onActivityResult
< import com.samourai.wallet.payload.PayloadUtil
< import com.samourai.wallet.paynym.PayNymHome
< import com.samourai.wallet.paynym.api.PayNymApiService
< import com.samourai.wallet.paynym.models.NymResponse
< import com.samourai.wallet.ricochet.RicochetMeta
< import com.samourai.wallet.segwit.bech32.Bech32Util
< import com.samourai.wallet.send.BlockedUTXO
< import com.samourai.wallet.send.MyTransactionOutPoint
< import com.samourai.wallet.send.SendActivity
< import com.samourai.wallet.send.SendActivity.isPSBT
< import com.samourai.wallet.send.batch.InputBatchSpendHelper.canParseAsBatchSpend
< import com.samourai.wallet.send.cahoots.ManualCahootsActivity
< import com.samourai.wallet.settings.SettingsActivity
< import com.samourai.wallet.stealth.StealthModeController
< import com.samourai.wallet.tools.ToolsBottomSheet
< import com.samourai.wallet.tools.viewmodels.Auth47ViewModel
< import com.samourai.wallet.tor.EnumTorState
< import com.samourai.wallet.tor.SamouraiTorManager
< import com.samourai.wallet.tor.TorState
< import com.samourai.wallet.tx.TxDetailsActivity
< import com.samourai.wallet.util.AppUpdateAvailableBottomSheet
< import com.samourai.wallet.util.CharSequenceX
< import com.samourai.wallet.util.PrefsUtil
< import com.samourai.wallet.util.PrivKeyReader
< import com.samourai.wallet.util.TimeOutUtil
< import com.samourai.wallet.util.func.FormatsUtil
< import com.samourai.wallet.util.func.WalletRefreshUtil
< import com.samourai.wallet.util.func.WalletUtil
< import com.samourai.wallet.util.func.executeFeaturePayNymUpdate
< import com.samourai.wallet.util.network.BlockExplorerUtil
< import com.samourai.wallet.util.tech.AppUtil
< import com.samourai.wallet.util.tech.LogUtil
< import com.samourai.wallet.util.tech.askNotificationPermission
< import com.samourai.wallet.utxos.UTXOSActivity
< import com.samourai.wallet.whirlpool.WhirlpoolMeta
< import com.samourai.wallet.widgets.ItemDividerDecorator
< import com.samourai.wallet.widgets.popUpMenu.popupMenu
< import com.squareup.picasso.Callback
< import com.squareup.picasso.Picasso
< import io.reactivex.Observable
< import io.reactivex.Single
< import io.reactivex.android.schedulers.AndroidSchedulers
< import io.reactivex.schedulers.Schedulers
< import kotlinx.coroutines.Dispatchers
< import kotlinx.coroutines.async
< import kotlinx.coroutines.delay
< import kotlinx.coroutines.launch
< import kotlinx.coroutines.sync.Semaphore
< import kotlinx.coroutines.sync.withPermit
< import kotlinx.coroutines.withContext
< import org.bitcoinj.crypto.MnemonicException.MnemonicLengthException
< import org.bitcoinj.script.Script
< import org.bouncycastle.util.encoders.Hex
< import org.json.JSONException
< import org.json.JSONObject
< import java.io.IOException
< import java.util.Collections
< import java.util.Objects.nonNull
<
<
< open class BalanceActivity : SamouraiActivity() {
< private var txs: MutableList<Tx>? = null
< private var ricochetQueueTask: RicochetQueueTask? = null
< private val balanceViewModel: BalanceViewModel by viewModels()
< private lateinit var binding: ActivityBalanceBinding
< private var menu: Menu? = null
< private val menuTorIcon: ImageView? = null
< private var executeQuitAppProcessStarted = false
< private val uiSemaphore: Semaphore = Semaphore(1)
<
< private var receiver: BroadcastReceiver = object : BroadcastReceiver() {
< override fun onReceive(context: Context, intent: Intent) {
< if (ACTION_INTENT == intent.action) {
< if (binding.progressBar != null) {
< showProgress()
< }
< val notifTx = intent.getBooleanExtra("notifTx", false)
< val fetch = intent.getBooleanExtra("fetch", false)
< val rbfHash: String?
< val blkHash: String?
< rbfHash = if (intent.hasExtra("rbf")) {
< intent.getStringExtra("rbf")
< } else {
< null
< }
< blkHash = if (intent.hasExtra("hash")) {
< intent.getStringExtra("hash")
< } else {
< null
< }
< val handler = Handler()
< handler.post {
< refreshTx(notifTx, false, false)
< if (this@BalanceActivity != null) {
< if (rbfHash != null) {
< MaterialAlertDialogBuilder(this@BalanceActivity)
< .setTitle(R.string.app_name)
< .setMessage(rbfHash + "\n\n" + getString(R.string.rbf_incoming))
< .setCancelable(true)
< .setPositiveButton(R.string.yes, DialogInterface.OnClickListener { dialog, whichButton -> doExplorerView(rbfHash) })
< .setNegativeButton(R.string.no, object : DialogInterface.OnClickListener {
< override fun onClick(dialog: DialogInterface, whichButton: Int) {
< }
< }).show()
< }
< }
< }
< }
< }
< }
< private var receiverDisplay: BroadcastReceiver = object : BroadcastReceiver() {
< override fun onReceive(context: Context, intent: Intent) {
< if (DISPLAY_INTENT == intent.action) {
< updateDisplay(true)
< checkDust()
< }
< }
< }
<
< private fun checkDust() {
< balanceViewModel.viewModelScope.launch {
< withContext(Dispatchers.Default) {
< val utxos = APIFactory.getInstance(this@BalanceActivity).getUtxos(false)
< val utxoWarnings = arrayListOf<MyTransactionOutPoint>()
< for (utxo in utxos) {
< val outpoints = utxo.outpoints
< for (out in outpoints) {
< val scriptBytes = out.scriptBytes
< var address: String? = null
< try {
< address = if (Bech32Util.getInstance().isBech32Script(Hex.toHexString(scriptBytes))) {
< Bech32Util.getInstance().getAddressFromScript(Hex.toHexString(scriptBytes))
< } else {
< Script(scriptBytes).getToAddress(SamouraiWallet.getInstance().currentNetworkParams).toString()
< }
< } catch (e: Exception) {
< }
< val path = APIFactory.getInstance(this@BalanceActivity).unspentPaths[address]
< if (path != null && path.startsWith("M/1/")) {
< continue
< }
< val hash = out.hash.toString()
< val idx = out.txOutputN
< val amount = out.value.longValue()
< val contains = BlockedUTXO.getInstance().contains(hash, idx) || BlockedUTXO.getInstance().containsNotDusted(hash, idx)
< val containsInPostMix = BlockedUTXO.getInstance().containsPostMix(hash, idx) || BlockedUTXO.getInstance().containsNotDustedPostMix(hash, idx)
< if (amount < BlockedUTXO.BLOCKED_UTXO_THRESHOLD && !contains && !containsInPostMix) {
< utxoWarnings.add(out);
< // BalanceActivity.this.runOnUiThread(new Runnable() {
< // @Override
< }
< }
< }
< if(! utxoWarnings.isEmpty()) {
< withContext(Dispatchers.Main) {
< utxoWarnings.forEach {
< val hash = it.hash.toString()
< val idx = it.txOutputN
< val amount = it.value.longValue()
< var message: String? = this@BalanceActivity.getString(R.string.dusting_attempt)
< message += "\n\n"
< message += this@BalanceActivity.getString(R.string.dusting_attempt_amount)
< message += " "
< message += FormatsUtil.formatBTC(amount)
< message += this@BalanceActivity.getString(R.string.dusting_attempt_id)
< message += " "
< message += "$hash-$idx"
< val dlg = MaterialAlertDialogBuilder(this@BalanceActivity)
< .setTitle(R.string.dusting_tx)
< .setMessage(message)
< .setCancelable(false)
< .setPositiveButton(R.string.dusting_attempt_mark_unspendable) { dialog, whichButton ->
< if (account == WhirlpoolMeta.getInstance(this@BalanceActivity).whirlpoolPostmix) {
< BlockedUTXO.getInstance().addPostMix(hash, idx, amount)
< } else {
< BlockedUTXO.getInstance().add(hash, idx, amount)
< }
< saveState()
< }.setNegativeButton(R.string.dusting_attempt_ignore) { dialog, whichButton ->
< if (account == WhirlpoolMeta.getInstance(this@BalanceActivity).whirlpoolPostmix) {
< BlockedUTXO.getInstance().addNotDustedPostMix(hash, idx)
< } else {
< BlockedUTXO.getInstance().addNotDusted(hash, idx)
< }
< saveState()
< }
< if (!isFinishing) {
< dlg.show()
< }
< }
< }
< }
< }
< }
< }
<
< override fun onCreate(savedInstanceState: Bundle?) {
< //Switch themes based on accounts (blue theme for whirlpool account)
< setSwitchThemes(true)
< super.onCreate(savedInstanceState)
< val comeFromPostmix = isFromPostmix()
< binding = ActivityBalanceBinding.inflate(layoutInflater)
< setContentView(binding.root)
< balanceViewModel.setAccount(account)
< if (account == DEPOSIT) {
< val biP47Util = BIP47Util.getInstance(applicationContext)
< biP47Util.payNymLogoLive.observe(this@BalanceActivity) {
< binding.toolbarIcon.setImageBitmap(it)
< }
< }
< makePaynymAvatarCache()
< requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
< setSupportActionBar(binding.toolbar)
< binding.rvTxes.layoutManager = LinearLayoutManager(this)
< val drawable = ContextCompat.getDrawable(this, R.drawable.divider_grey)
< binding.rvTxes.addItemDecoration(ItemDividerDecorator(drawable))
< txs = ArrayList()
< /*
< findViewById<View>(R.id.whirlpool_fab).setOnClickListener { view: View? ->
< val intent = Intent(this@BalanceActivity, WhirlpoolHome::class.java)
< startActivity(intent)
< binding.fabMenu.toggle(true)
< }
< */
< binding.sendFab.setOnClickListener(View.OnClickListener { view: View? ->
<
< val isPostmixAccount = account == POSTMIX
<
< val activityType =
< if (isPostmixAccount) SendActivity::class.java
< else AccountSelectionActivity::class.java
<
< val intent = Intent(this@BalanceActivity, activityType)
< intent.putExtra("via_menu", true)
< if (isPostmixAccount) {
< intent.putExtra("_account", account)
< }
< startActivity(intent)
< binding.fabMenu.toggle(true)
< })
< if (!comeFromPostmix) {
< loadBalance()
< }
< binding.receiveFab.setOnClickListener { view: View? ->
< binding.fabMenu.toggle(true)
< val hdw = HD_WalletFactory.getInstance(this@BalanceActivity).get()
< if (hdw != null) {
< val intent = Intent(this@BalanceActivity, ReceiveActivity::class.java)
< startActivity(intent)
< }
< }
< binding.paynymFab.setOnClickListener { view: View? ->
< binding.fabMenu.toggle(true)
< val intent = Intent(this@BalanceActivity, PayNymHome::class.java)
< startActivity(intent)
< }
< binding.txSwipeContainer.setOnRefreshListener(OnRefreshListener {
< doClipboardCheck()
< refreshTx(false, true, false)
< binding.txSwipeContainer.isRefreshing = false
< showProgress()
< })
<
< binding.appBar.addOnOffsetChangedListener { appBarLayout, verticalOffset ->
< if (Math.abs(verticalOffset) == appBarLayout.totalScrollRange) {
< binding.utxoIcon.visibility = View.GONE
< } else if (verticalOffset == 0) {
< binding.utxoIcon.visibility = View.VISIBLE
< } else {
< binding.utxoIcon.visibility = View.GONE
< }
< }
<
< val filter = IntentFilter(ACTION_INTENT)
< LocalBroadcastManager.getInstance(this@BalanceActivity).registerReceiver(receiver, filter)
< val filterDisplay = IntentFilter(DISPLAY_INTENT)
< LocalBroadcastManager.getInstance(this@BalanceActivity).registerReceiver(receiverDisplay, filterDisplay)
<
< balanceViewModel.viewModelScope.launch(Dispatchers.IO) {
< if (PrefsUtil.getInstance(applicationContext).getValue(PrefsUtil.AUTO_BACKUP, true)) {
< if (!hasPermissions()) askPermission(this@BalanceActivity)
< }
< }
<
< if (!comeFromPostmix) {
< doFeaturePayNymUpdate()
< }
<
< if (RicochetMeta.getInstance(this@BalanceActivity).queue.size > 0) {
< if (ricochetQueueTask == null || ricochetQueueTask!!.status == AsyncTask.Status.FINISHED) {
< ricochetQueueTask = RicochetQueueTask()
< ricochetQueueTask!!.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR)
< }
< }
< if (!AppUtil.getInstance(this@BalanceActivity).isClipboardSeen) {
< doClipboardCheck()
< }
< setUpTor()
< initViewModel()
< if (account == DEPOSIT) {
< binding.toolbarIcon.setOnClickListener {
< showToolOptions(it)
< }
< if (! comeFromPostmix) {
< val delayedHandler = Handler()
< delayedHandler.postDelayed({
< var notifTx = intent.getBooleanExtra("notifTx", false)
< refreshTx(notifTx, false, true)
< updateDisplay(false)
< }, 100L)
< }
< } else {
< binding.toolbarIcon.visibility = View.GONE
< binding.toolbar.setTitleMargin(0, 0, 0, 0)
< binding.toolbar.titleMarginEnd = -50
< binding.toolbar.setNavigationIcon(R.drawable.ic_piggy_bank )
< binding.toolbar.setNavigationOnClickListener {
< val intent = Intent(this, BalanceActivity::class.java)
< intent.putExtra("_account", DEPOSIT)
< intent.putExtra("come_from_postmix", true)
< intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
< finish()
< startActivity(intent)
< }
< binding.receiveFab.visibility = View.GONE
< //binding.whirlpoolFab.visibility = View.GONE
< binding.paynymFab.visibility = View.GONE
< Handler().postDelayed({ updateDisplay(true) }, 600L)
< }
< balanceViewModel.loadOfflineData()
<
< updateDisplay(false)
< checkDeepLinks()
< doExternalBackUp()
<
< balanceViewModel.viewModelScope.launch {
< withContext(Dispatchers.Main) {
< askNotificationPermission(this@BalanceActivity)
< }
< }
< }
<
< private fun showAppUpdate(show: Boolean) {
< if (appUpdateShowed) return
< if (show && nonNull(SamouraiWallet.getInstance().releaseNotes)) {
< AppUtil.getInstance(this).setHasUpdateBeenShown(true)
< appUpdateShowed = true
< val bottomSheetFragment = AppUpdateAvailableBottomSheet(SamouraiWallet.getInstance().releaseNotes.getString("version"))
< bottomSheetFragment.show(supportFragmentManager, bottomSheetFragment.tag)
< return
< }
< }
<
< private fun loadBalance() {
< balanceViewModel.viewModelScope.launch(Dispatchers.IO) {
< val is_sat_prefs = PrefsUtil.getInstance(this@BalanceActivity)
< .getValue(PrefsUtil.IS_SAT, false)
<
< val payloadWrapper : MutableList<JSONObject> = Lists.newArrayList();
< val job = balanceViewModel.viewModelScope.launch(Dispatchers.IO) {
< payloadWrapper.add(PayloadUtil.getInstance(this@BalanceActivity).payload)
< }
<
< balanceViewModel.viewModelScope.launch(Dispatchers.Main) {
< job.invokeOnCompletion { it ->
< if (it != null) {
< AppUtil.getInstance(applicationContext).restartApp()
< Log.e(TAG, "issue on payload loading")
< it.printStackTrace()
< } else {
< val payload = if (payloadWrapper.size == 1) payloadWrapper[0] else null
< if (account == DEPOSIT &&
< payload != null &&
< payload.has("meta") &&
< payload.getJSONObject("meta").has("prev_balance")) {
<
< try {
< setBalance(payload.getJSONObject("meta").getLong("prev_balance"), is_sat_prefs)
< } catch (e: Exception) {
< Log.e(TAG, "issue on setBalance()", e)
< setBalance(0L, is_sat_prefs)
< }
<
< } else {
< if (account == DEPOSIT) {
< Log.e(TAG, "issue on payload loading")
< }
< setBalance(0L, is_sat_prefs)
< }
< }
< }
< }
< }
< }
<
< private fun showToolOptions(it: View) {
<
< balanceViewModel.viewModelScope.launch(Dispatchers.IO) {
<
< val bitmapImage = BIP47Util.getInstance(applicationContext).payNymLogoLive.value
< var drawable = ContextCompat.getDrawable(this@BalanceActivity, R.drawable.ic_ashigaru_logo)
< var nym = PrefsUtil.getInstance(applicationContext)
< .getValue(PrefsUtil.PAYNYM_BOT_NAME, BIP47Meta.getInstance().getDisplayLabel(BIP47Util.getInstance(applicationContext).paymentCode.toString()))
< if (bitmapImage != null) {
< drawable = BitmapDrawable(resources, bitmapImage)
< }
< if (nym.isNullOrEmpty()) {
< nym = BIP47Meta.getInstance().getDisplayLabel(BIP47Util.getInstance(applicationContext).paymentCode.toString())
< }
<
< withContext(Dispatchers.Main) {
< val toolWindowSize = applicationContext.resources.displayMetrics.density * 220;
< val popupMenu = popupMenu {
< fixedContentWidthInPx = toolWindowSize.toInt()
< style = R.style.Theme_Samourai_Widget_MPM_Menu_Dark
< section {
< item {
< label = nym
< iconDrawable = drawable
< iconSize = 34
< labelColor = ContextCompat.getColor(applicationContext, R.color.white)
< disableTint = true
< iconShapeAppearanceModel = ShapeAppearanceModel().toBuilder()
< .setAllCornerSizes(resources.getDimension(R.dimen.qr_image_corner_radius))
< .build()
< callback = {
< val intent = Intent(this@BalanceActivity, PayNymHome::class.java)
< startActivity(intent)
< }
< }
< item {
< label = "Collaborate"
< iconSize = 18
< callback = {
< val intent = Intent(this@BalanceActivity, CollaborateActivity::class.java)
< startActivity(intent)
< }
< icon = R.drawable.ic_connect_without_contact
< }
< item {
< label = "Tools"
< icon = R.drawable.ic_tools
< iconSize = 18
< hasNestedItems
< callback = {
< ToolsBottomSheet.showTools(supportFragmentManager)
< }
< }
< }
< section {
<
< item {
< label = "Pairing"
< icon = R.drawable.pairing_icon
< iconSize = 18
< hasNestedItems
< callback = {
< val intent = Intent(this@BalanceActivity, PairingMenuActivity::class.java)
< startActivity(intent)
< }
< }
<
< item {
< label = getString(R.string.action_settings)
< icon = R.drawable.ic_cog
< iconSize = 18
< callback = {
< TimeOutUtil.getInstance().updatePin()
< val intent = Intent(this@BalanceActivity, SettingsActivity::class.java)
< startActivity(intent)
< }
< }
< item {
< label = "Exit Wallet"
< iconSize = 18
< iconColor = ContextCompat.getColor(this@BalanceActivity, R.color.mpm_red)
< labelColor = ContextCompat.getColor(this@BalanceActivity, R.color.mpm_red)
< icon = R.drawable.ic_baseline_power_settings_new_24
< callback = {
< this@BalanceActivity.onBackPressed()
< }
< }
< }
< }
< popupMenu.show(this@BalanceActivity, it)
< }
< }
< }
<
< private fun hideProgress() {
< balanceViewModel.viewModelScope.launch(Dispatchers.IO) {
< delay(150L)
< withContext(Dispatchers.Main) {
< uiSemaphore.withPermit {
< val loading = AppUtil.getInstance(applicationContext).walletLoading.value?:false
< if (!loading) {
< val progressIndicator = binding.progressBar
< if (progressIndicator.isVisible) {
< progressIndicator.apply {
< hide()
< }
< }
< }
< }
< }
< }
< }
<
< private fun showProgress() {
< balanceViewModel.viewModelScope.launch(Dispatchers.IO) {
< delay(150L)
< withContext(Dispatchers.Main) {
< uiSemaphore.withPermit {
< val loading = AppUtil.getInstance(applicationContext).walletLoading.value?:false
< if (loading) {
< val progressIndicator = binding.progressBar
< if (!progressIndicator.isVisible) {
< progressIndicator.apply {
< isIndeterminate = true
< show()
< }
< }
< }
< }
< }
< }
< }
<
< private fun checkDeepLinks() {
< val bundle = intent.extras ?: return
< if (bundle.containsKey("pcode") || bundle.containsKey("uri") || bundle.containsKey("amount")) {
< if (bundle.containsKey("uri")) {
< if (bundle.getString("uri")?.startsWith("auth47") == true) {
< ToolsBottomSheet.showTools(supportFragmentManager, ToolsBottomSheet.ToolType.AUTH47,
< bundle = Bundle().apply {
< putString("KEY", bundle.getString("uri"))
< })
< return;
< }
< }
< if (balanceViewModel.balance.value != null) bundle.putLong("balance", balanceViewModel.balance.value!!)
< val intent = Intent(this, AccountSelectionActivity::class.java)
< intent.putExtra("_account", account)
< intent.putExtras(bundle)
< startActivity(intent)
< }
< }
<
< override fun onNewIntent(intent: Intent) {
< super.onNewIntent(intent)
< setIntent(intent)
< }
<
< private fun initViewModel() {
< val adapter = TxAdapter(applicationContext, ArrayList(), account)
< adapter.setClickListener { position: Int, tx: Tx -> txDetails(tx) }
< binding.rvTxes.adapter = adapter
< val is_sat_prefs = PrefsUtil.getInstance(this@BalanceActivity).getValue(PrefsUtil.IS_SAT, false)
< balanceViewModel.balance.observe(this) { balance: Long? ->
< if (balance == null) {
< return@observe
< }
< if (balance < 0) {
< return@observe
< }
< if (binding.progressBar.visibility == View.VISIBLE && balance <= 0) {
< return@observe
< }
< setBalance(balance, is_sat_prefs)
< }
< adapter.setTxes(balanceViewModel.txs.value)
< setBalance(balanceViewModel.balance.value, is_sat_prefs)
< balanceViewModel.satState.observe(this) { state: Boolean? ->
< var isSats = false
< if (state != null) {
< isSats = state
< }
< setBalance(balanceViewModel.balance.value, isSats)
< adapter.notifyDataSetChanged()
< }
< balanceViewModel.txs.observe(this) { list -> adapter.setTxes(list) }
< binding.toolbarLayout.setOnClickListener { v: View? ->
< val is_sat = balanceViewModel.toggleSat()
< PrefsUtil.getInstance(this@BalanceActivity).setValue(PrefsUtil.IS_SAT, is_sat)
< }
< binding.toolbarLayout.setOnLongClickListener {
< val intent = Intent(this@BalanceActivity, UTXOSActivity::class.java)
< intent.putExtra("_account", account)
< startActivityForResult(intent, UTXO_REQUESTCODE)
< false
< }
<
< binding.utxoIcon.setOnClickListener {
< val intent = Intent(this@BalanceActivity, UTXOSActivity::class.java)
< intent.putExtra("_account", account)
< startActivityForResult(intent, UTXO_REQUESTCODE)
< }
<
< binding.utxoIcon.setOnLongClickListener {
< if (SamouraiWallet.getInstance().isTestNet) {
< SamouraiWallet.MOCK_FEE = !SamouraiWallet.MOCK_FEE
< refreshTx(false, true, false)
< binding.txSwipeContainer.isRefreshing = false
< showProgress()
< }
< false
< }
< }
<
< private fun setBalance(balance: Long?, isSat: Boolean) {
< if (balance == null) {
< return
< }
< balanceViewModel.viewModelScope.launch(Dispatchers.Main) {
< if (supportActionBar != null) {
< TransitionManager.beginDelayedTransition(binding.toolbarLayout, ChangeBounds())
< val displayAmount = if (isSat) FormatsUtil.formatSats(balance) else FormatsUtil.formatBTC(balance)
< binding.toolbar.title = displayAmount
< title = displayAmount
< binding.toolbarLayout.title = displayAmount
< }
< }
< }
<
< public override fun onResume() {
< super.onResume()
< executeQuitAppProcessStarted = false;
<
< showProgress()
< AppUtil.getInstance(applicationContext).walletLoading.observe(this) {
< if (it) {
< showProgress()
< } else {
< hideProgress()
< }
< }
< if (! isFromPostmix() && intent.getBooleanExtra("refresh", false)) {
< balanceViewModel.viewModelScope.launch {
< withContext(Dispatchers.IO) {
< async {
< WalletRefreshUtil.refreshWallet(
< notifTx = false,
< launch = false,
< context = applicationContext)
< }
< }
< }
< }
<
< AppUtil.getInstance(applicationContext).hasUpdateBeenShown.observe(this) {
< showAppUpdate(!it)
< }
<
< AppUtil.getInstance(this@BalanceActivity).checkTimeOut()
< try {
< val isSatPrefs = PrefsUtil.getInstance(applicationContext).getValue(PrefsUtil.IS_SAT, false)
< if (isSatPrefs != balanceViewModel.satState.value) {
< balanceViewModel.toggleSat()
< }
< } catch (e: Exception) {
< LogUtil.error(TAG, e)
< }
< }
<
< fun createTag(text: String?): View {
< val scale = resources.displayMetrics.density
< val lparams = LinearLayout.LayoutParams(
< LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT
< )
< val textView = TextView(applicationContext)
< textView.text = text
< textView.setTextColor(ContextCompat.getColor(applicationContext, R.color.white))
< textView.layoutParams = lparams
< textView.setBackgroundResource(R.drawable.tag_round_shape)
< textView.setPadding((8 * scale + 0.5f).toInt(), (6 * scale + 0.5f).toInt(), (8 * scale + 0.5f).toInt(), (6 * scale + 0.5f).toInt())
< textView.typeface = Typeface.DEFAULT_BOLD
< textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 11f)
< return textView
< }
<
< private fun makePaynymAvatarCache() {
< try {
< balanceViewModel.viewModelScope.launch(Dispatchers.IO) {
<
< if (PrefsUtil.getInstance(applicationContext).getValue(PrefsUtil.PAYNYM_BOT_NAME, "").isNullOrEmpty()
< && PrefsUtil.getInstance(applicationContext).getValue(PrefsUtil.PAYNYM_CLAIMED,false)) {
< val strPaymentCode = BIP47Util.getInstance(application).paymentCode.toString()
< val apiService = PayNymApiService.getInstance(strPaymentCode, getApplication());
< balanceViewModel.viewModelScope.launch(Dispatchers.IO) {
< try {
< val response = apiService.getNymInfo()
< if (response.isSuccessful) {
< val responseJson = response.body?.string()
< if (responseJson != null) {
< val jsonObject = JSONObject(responseJson)
< val nym = Gson().fromJson(jsonObject.toString(), NymResponse::class.java);
< PrefsUtil.getInstance(applicationContext).setValue(PrefsUtil.PAYNYM_BOT_NAME, nym.nymName)
<
< } else
< throw Exception("Invalid response ")
< }
< } catch (_: Exception) {
<
< }
< }
< }
<
< if (!BIP47Util.getInstance(applicationContext).avatarImage().exists()) {
< loadAvatar()
< } else {
< balanceViewModel.viewModelScope.launch(Dispatchers.IO) {
< val bitmap = BitmapFactory.decodeFile(BIP47Util.getInstance(applicationContext).avatarImage().path)
< if (bitmap != null) {
< BIP47Util.getInstance(applicationContext).setAvatar(bitmap)
< } else {
< loadAvatar()
< }
< }
< }
<
< val paymentCodes = ArrayList(BIP47Meta.getInstance().getSortedByLabels(false, true))
< for (code in paymentCodes) {
< Picasso.get()
< .load(WebUtil.PAYNYM_API + code + "/avatar").fetch(object : Callback {
< override fun onSuccess() {
< /*NO OP*/
< }
<
< override fun onError(e: Exception) {
< /*NO OP*/
< }
< })
< }
< }
<
< } catch (ignored: Exception) {
< }
< }
<
< private fun loadAvatar() {
< BIP47Util.getInstance(applicationContext).fetchBotImage()
< .subscribe()
< .apply {
< registerDisposable(this)
< }
< }
<
< public override fun onDestroy() {
< LocalBroadcastManager.getInstance(this@BalanceActivity).unregisterReceiver(receiver)
< LocalBroadcastManager.getInstance(this@BalanceActivity).unregisterReceiver(receiverDisplay)
<
< if (PrefsUtil.getInstance(this.application).getValue(StealthModeController.PREF_ENABLED, false)) {
< StealthModeController.enableStealth(applicationContext)
< }
< super.onDestroy()
< }
<
< override fun onCreateOptionsMenu(menu: Menu): Boolean {
< menuInflater.inflate(R.menu.main, menu)
< menu.findItem(R.id.action_mock_fees).isVisible = false
< menu.findItem(R.id.action_refresh).isVisible = false
< menu.findItem(R.id.action_share_receive).isVisible = false
< menu.findItem(R.id.action_ricochet).isVisible = false
< menu.findItem(R.id.action_empty_ricochet).isVisible = false
< menu.findItem(R.id.action_sign).isVisible = false
< menu.findItem(R.id.action_fees).isVisible = false
< menu.findItem(R.id.action_batch).isVisible = false
< menu.findItem(R.id.action_backup).isVisible = false
< menu.findItem(R.id.action_utxo).isVisible = false
< WhirlpoolMeta.getInstance(applicationContext)
< if (account == POSTMIX) {
< menu.findItem(R.id.action_network_dashboard).isVisible = false
< menu.findItem(R.id.action_postmix_balance).isVisible = false
< val item = menu.findItem(R.id.action_menu_account)
< item.actionView = createTag(" POST-MIX ")
< item.isVisible = true
< item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
< }
< this.menu = menu
< return super.onCreateOptionsMenu(menu)
< }
<
< override fun onOptionsItemSelected(item: MenuItem): Boolean {
< // Handle action bar item clicks here. The action bar will
< // automatically handle clicks on the Home/Up button, so long
< // as you specify a parent activity in AndroidManifest.xml.
< val id = item.itemId
< if (id == android.R.id.home) {
< finish()
< return super.onOptionsItemSelected(item)
< }
< if (id == R.id.action_mock_fees) {
< SamouraiWallet.MOCK_FEE = !SamouraiWallet.MOCK_FEE
< refreshTx(false, true, false)
< binding.txSwipeContainer.isRefreshing = false
< showProgress()
< return super.onOptionsItemSelected(item)
< }
< if (id == R.id.action_postmix_balance) {
< val intent = Intent(this, BalanceActivity::class.java)
< intent.putExtra("_account", POSTMIX)
< intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
< finish()
< startActivity(intent)
< return super.onOptionsItemSelected(item)
< }
<
< // noinspection SimplifiableIfStatement
< if (id == R.id.action_network_dashboard) {
< startActivity(Intent(this, NetworkDashboard::class.java))
< } // noinspection SimplifiableIfStatement
< /*
< if (id == R.id.action_support) {
< ActivityHelper.launchSupportPageInBrowser(this, SamouraiTorManager.isConnected())
< } else */
< if (id == R.id.action_utxo) {
< doUTXO()
< } else if (id == R.id.action_backup) {
< if (SamouraiWallet.getInstance().hasPassphrase(this@BalanceActivity)) {
< if (HD_WalletFactory.getInstance(this@BalanceActivity).get() != null && SamouraiWallet.getInstance().hasPassphrase(this@BalanceActivity)) {
< doBackup(HD_WalletFactory.getInstance(this@BalanceActivity).get().passphrase)
< }
< } else {
< val builder = MaterialAlertDialogBuilder(this)
< builder.setTitle(R.string.enter_backup_password)
< val view = layoutInflater.inflate(R.layout.password_input_dialog_layout, null)
< val password = view.findViewById<EditText>(R.id.restore_dialog_password_edittext)
< val message = view.findViewById<TextView>(R.id.dialogMessage)
< message.setText(R.string.backup_password)
< builder.setPositiveButton(R.string.confirm) { dialog: DialogInterface, which: Int ->
< val pw = password.text.toString()
< if (pw.length >= AppUtil.MIN_BACKUP_PW_LENGTH && pw.length <= AppUtil.MAX_BACKUP_PW_LENGTH) {
< doBackup(pw)
< } else {
< Toast.makeText(applicationContext, R.string.password_error, Toast.LENGTH_SHORT).show()
< }
< dialog.dismiss()
< }
< builder.setNegativeButton(R.string.cancel) { dialog: DialogInterface, which: Int -> dialog.dismiss() }
< builder.setView(view)
< builder.show()
< }
< } else if (id == R.id.action_scan_qr) {
< doScan()
< } else {
< }
< return super.onOptionsItemSelected(item)
< }
<
< private fun setUpTor() {
< SamouraiTorManager.getTorStateLiveData().observe(this) { torState: TorState ->
<
< if (torState.state == EnumTorState.ON) {
< balanceViewModel.viewModelScope.launch(Dispatchers.IO) {
< PrefsUtil.getInstance(this@BalanceActivity).setValue(PrefsUtil.ENABLE_TOR, true)
< balanceViewModel.viewModelScope.launch(Dispatchers.Main) {
< binding.progressBar.visibility = View.INVISIBLE
< menuTorIcon?.setImageResource(R.drawable.tor_on)
< }
< }
<
< } else if (torState.state == EnumTorState.STARTING) {
< binding.progressBar.visibility = View.VISIBLE
< menuTorIcon?.setImageResource(R.drawable.tor_on)
<
< } else {
< balanceViewModel.viewModelScope.launch(Dispatchers.IO) {
< if (torState.state == EnumTorState.OFF && !executeQuitAppProcessStarted) {
< PrefsUtil.getInstance(this@BalanceActivity).setValue(PrefsUtil.ENABLE_TOR, false)
< }
< balanceViewModel.viewModelScope.launch(Dispatchers.Main) {
< binding.progressBar.visibility = View.INVISIBLE
< menuTorIcon?.setImageResource(R.drawable.tor_off)
< }
< }
< }
< }
< }
<
< public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
< super.onActivityResult(requestCode, resultCode, data)
< onActivityResult(requestCode, resultCode, data, application)
< if (resultCode == RESULT_OK && requestCode == SCAN_COLD_STORAGE) {
< if (data?.getStringExtra(ZBarConstants.SCAN_RESULT) != null) {
< val strResult = data.getStringExtra(ZBarConstants.SCAN_RESULT)
< doPrivKey(strResult)
< }
< } else if (resultCode == RESULT_CANCELED && requestCode == SCAN_COLD_STORAGE) {
< } else if (resultCode == RESULT_OK && requestCode == SCAN_QR) {
<
< if (data?.getStringExtra(ZBarConstants.SCAN_RESULT) != null) {
< val strResult = data.getStringExtra(ZBarConstants.SCAN_RESULT)
< val params = SamouraiWallet.getInstance().currentNetworkParams
< val privKeyReader = PrivKeyReader(strResult, params)
< try {
< if (privKeyReader.format != null) {
< doPrivKey(strResult!!.trim { it <= ' ' })
< } else if (strResult?.lowercase()?.startsWith(Auth47ViewModel.AUTH_SCHEME.lowercase()) == true) {
< ToolsBottomSheet.showTools(supportFragmentManager, ToolsBottomSheet.ToolType.AUTH47,
< bundle = Bundle().apply {
< putString("KEY", strResult)
< })
< } else if (Cahoots.isCahoots(strResult!!.trim { it <= ' ' })) {
< val cahootIntent = ManualCahootsActivity.createIntentResume(this, account, strResult.trim { it <= ' ' })
< startActivity(cahootIntent)
< } else if (isPSBT(strResult.trim { it <= ' ' })) {
< PSBTUtil.getInstance(this@BalanceActivity).doPSBT(strResult.trim { it <= ' ' })
< } else if (DojoUtil.getInstance(this@BalanceActivity).isValidPairingPayload(strResult.trim { it <= ' ' })) {
< val intent = Intent(this@BalanceActivity, NetworkDashboard::class.java)
< intent.putExtra("params", strResult.trim { it <= ' ' })
< startActivity(intent)
< } else {
< val intent = Intent(this@BalanceActivity, AccountSelectionActivity::class.java)
< intent.putExtra("uri", strResult.trim { it <= ' ' })
< intent.putExtra("_account", account)
< startActivity(intent)
< }
< } catch (e: Exception) {
< }
< }
< }
< if (resultCode == RESULT_OK && requestCode == UTXO_REQUESTCODE) {
< refreshTx(false, false, false)
< showProgress()
< } else {
< }
< }
<
< override fun onBackPressed() {
< if (account == DEPOSIT || account == POSTMIX) {
< val builder = MaterialAlertDialogBuilder(this)
< builder.setMessage(R.string.ask_you_sure_exit)
< val alert = builder.create()
< alert.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.yes)) { dialog: DialogInterface?, id: Int ->
< executeQuitAppProcesses()
< }
< alert.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.no)) { dialog: DialogInterface, id: Int -> dialog.dismiss() }
< alert.show()
< } else {
< super.onBackPressed()
< }
< }
<
< private fun doExternalBackUp() {
< balanceViewModel.viewModelScope.launch(Dispatchers.IO) {
< try {
< if (hasPermissions() && PrefsUtil.getInstance(application).getValue(PrefsUtil.AUTO_BACKUP, false)) {
< val disposable = Observable.fromCallable {
< PayloadUtil.getInstance(this@BalanceActivity).saveWalletToJSON(CharSequenceX(AccessFactory.getInstance(this@BalanceActivity).guid + AccessFactory.getInstance(this@BalanceActivity).pin))
< true
< }.subscribeOn(Schedulers.io())
< .observeOn(AndroidSchedulers.mainThread()).subscribe({ t: Boolean? -> }) { throwable: Throwable? -> LogUtil.error(TAG, throwable) }
< registerDisposable(disposable)
< }
< } catch (exception: Exception) {
< LogUtil.error(TAG, exception)
< }
< }
< }
<
< private fun executeQuitAppProcesses() {
<
< executeQuitAppProcessStarted = true;
< appUpdateShowed = false;
<
< try {
< if (hasPermissions() &&
< PrefsUtil.getInstance(application).getValue(PrefsUtil.AUTO_BACKUP, false)) {
<
< val disposable = Observable.fromCallable {
< PayloadUtil.getInstance(this@BalanceActivity)
< .saveWalletToJSON(CharSequenceX(
< AccessFactory.getInstance(this@BalanceActivity).guid +
< AccessFactory.getInstance(this@BalanceActivity).pin))
< true
< }.subscribeOn(Schedulers.io())
< .observeOn(AndroidSchedulers.mainThread())
< .subscribe({ t: Boolean? ->
< stopingServices()
< }) { throwable: Throwable? ->
< LogUtil.error(TAG, throwable)
< stopingServices()
< }
< registerDisposable(disposable)
< } else {
< stopingServices()
< }
< } catch (exception: Exception) {
< LogUtil.error(TAG, exception)
< stopingServices()
< }
< }
<
< private fun stopingServices() {
< WalletUtil.stop(this);
< super.onBackPressed()
< }
<
< private fun updateDisplay(fromRefreshService: Boolean) {
< val txDisposable = getTxes(account)
< .subscribeOn(Schedulers.io())
< .observeOn(AndroidSchedulers.mainThread())
< .subscribe { txes: List<Tx>?, throwable: Throwable? ->
< throwable?.printStackTrace()
< if (txes != null) {
< if (txes.isNotEmpty()) {
< balanceViewModel.setTx(txes)
< } else {
< if (balanceViewModel.txs.value != null && balanceViewModel.txs.value!!.size == 0) {
< balanceViewModel.setTx(txes)
< }
< }
< Collections.sort(txes, TxMostRecentDateComparator())
< txs!!.clear()
< txs!!.addAll(txes)
< }
< if (binding.progressBar.visibility == View.VISIBLE &&
< fromRefreshService &&
< !(AppUtil.getInstance(applicationContext).walletLoading.value?:false)) {
<
< hideProgress()
< }
< }
< val balanceDisposable = getBalance(account)
< .subscribeOn(Schedulers.io())
< .observeOn(AndroidSchedulers.mainThread())
< .subscribe { balance: Long?, throwable: Throwable? ->
< throwable?.printStackTrace()
< balanceViewModel.postNewBalance(balance)
< }
< registerDisposable(balanceDisposable)
< registerDisposable(txDisposable)
< // displayBalance();
< // txAdapter.notifyDataSetChanged();
< }
<
< private fun getTxes(account: Int): Single<List<Tx>> {
< return Single.fromCallable {
< var loadedTxes: List<Tx> = ArrayList()
< if (account == 0) {
< loadedTxes = APIFactory.getInstance(this@BalanceActivity).allXpubTxs
< } else if (account == WhirlpoolMeta.getInstance(applicationContext).whirlpoolPostmix) {
< loadedTxes = APIFactory.getInstance(this@BalanceActivity).allPostMixTxs
< }
< loadedTxes
< }
< }
<
< private fun getBalance(account: Int): Single<Long> {
< return Single.fromCallable {
< var loadedBalance = 0L
< if (account == 0) {
< loadedBalance = APIFactory.getInstance(this@BalanceActivity).xpubBalance
< } else if (account == WhirlpoolMeta.getInstance(applicationContext).whirlpoolPostmix) {
< loadedBalance = APIFactory.getInstance(this@BalanceActivity).xpubPostMixBalance
< }
< loadedBalance
< }
< }
<
< private fun doSettings() {
< TimeOutUtil.getInstance().updatePin()
< val intent = Intent(this@BalanceActivity, SettingsActivity::class.java)
< startActivity(intent)
< }
<
< var utxoListResult = registerForActivityResult(
< ActivityResultContracts.StartActivityForResult()
< ) {
< run {
< showProgress()
< refreshTx(false, false, false)
< }
< }
<
< private fun doUTXO() {
< val intent = Intent(this@BalanceActivity, UTXOSActivity::class.java)
< intent.putExtra("_account", account)
< utxoListResult.launch(intent)
< }
<
< private fun doScan() {
< val cameraFragmentBottomSheet = ScanFragment()
< cameraFragmentBottomSheet.show(supportFragmentManager, cameraFragmentBottomSheet.tag)
< cameraFragmentBottomSheet.setOnScanListener { code ->
< cameraFragmentBottomSheet.dismissAllowingStateLoss()
< val params = SamouraiWallet.getInstance().currentNetworkParams
< val privKeyReader = PrivKeyReader(code, params)
< try {
< when {
< canParseAsBatchSpend(code) -> {
< launchBatchSpend(code)
< }
< privKeyReader.format != null -> {
< doPrivKey(code.trim { it <= ' ' })
< }
< code.lowercase().startsWith(Auth47ViewModel.AUTH_SCHEME) -> {
< ToolsBottomSheet.showTools(supportFragmentManager, ToolsBottomSheet.ToolType.AUTH47,
< bundle = Bundle().apply {
< putString("KEY", code)
< })
< }
< Cahoots.isCahoots(code.trim { it <= ' ' }) -> {
< val cahootIntent = ManualCahootsActivity.createIntentResume(this, account, code.trim { it <= ' ' })
< startActivity(cahootIntent)
< }
< isPSBT(code.trim { it <= ' ' }) -> {
< ToolsBottomSheet.showTools(supportFragmentManager, ToolsBottomSheet.ToolType.PSBT,
< bundle = Bundle().apply {
< putString("KEY", code)
< })
< }
< DojoUtil.getInstance(this@BalanceActivity).isValidPairingPayload(code.trim { it <= ' ' }) -> {
< val intent = Intent(this@BalanceActivity, NetworkDashboard::class.java)
< intent.putExtra("params", code.trim { it <= ' ' })
< startActivity(intent)
< }
< else -> {
<
< val isPostmixAccount = account == POSTMIX
<
< val activityType =
< if (isPostmixAccount) SendActivity::class.java
< else AccountSelectionActivity::class.java
<
< val intent = Intent(this@BalanceActivity, activityType)
< intent.putExtra("uri", code.trim { it <= ' ' })
< if (isPostmixAccount) {
< intent.putExtra("_account", account)
< }
< startActivity(intent)
< }
< }
< } catch (e: Exception) {
< }
< }
< }
<
< private fun launchBatchSpend(inputBatchSpendAsJson: String) {
< val intent = Intent(this@BalanceActivity, AccountSelectionActivity::class.java)
< intent.putExtra("inputBatchSpend", inputBatchSpendAsJson)
< startActivity(intent)
< }
<
< private fun doSweepViaScan() {
< val cameraFragmentBottomSheet = CameraFragmentBottomSheet()
< cameraFragmentBottomSheet.show(supportFragmentManager, cameraFragmentBottomSheet.tag)
< cameraFragmentBottomSheet.setQrCodeScanListener { code: String ->
< cameraFragmentBottomSheet.dismissAllowingStateLoss()
< val params = SamouraiWallet.getInstance().currentNetworkParams
< val privKeyReader = PrivKeyReader(code, params)
< try {
< when {
< privKeyReader.format != null -> {
< doPrivKey(code.trim { it <= ' ' })
< }
< Cahoots.isCahoots(code.trim { it <= ' ' }) -> {
< val cahootIntent = ManualCahootsActivity.createIntentResume(this, account, code.trim { it <= ' ' })
< startActivity(cahootIntent)
< }
< isPSBT(code.trim { it <= ' ' }) -> {
< PSBTUtil.getInstance(this@BalanceActivity).doPSBT(code.trim { it <= ' ' })
< }
< DojoUtil.getInstance(this@BalanceActivity).isValidPairingPayload(code.trim { it <= ' ' }) -> {
< Toast.makeText(this@BalanceActivity, "Samourai Dojo full node coming soon.", Toast.LENGTH_SHORT).show()
< }
< else -> {
< val intent = Intent(this@BalanceActivity, AccountSelectionActivity::class.java)
< intent.putExtra("uri", code.trim { it <= ' ' })
< intent.putExtra("_account", account)
< startActivity(intent)
< }
< }
< } catch (e: Exception) {
< }
< }
< }
<
< private fun doPrivKey(data: String?) {
<
< val params = SamouraiWallet.getInstance().currentNetworkParams
< var privKeyReader: PrivKeyReader? = null
< var format: String? = null
< try {
< privKeyReader = PrivKeyReader(data, params)
< format = privKeyReader.format
< } catch (e: Exception) {
< Toast.makeText(this@BalanceActivity, e.message, Toast.LENGTH_SHORT).show()
< return
< }
< if (format != null) {
< ToolsBottomSheet.showTools(supportFragmentManager, ToolsBottomSheet.ToolType.SWEEP,
< bundle = Bundle().apply {
< putString("KEY", data)
< })
< } else {
< Toast.makeText(this@BalanceActivity, R.string.cannot_recognize_privkey, Toast.LENGTH_SHORT).show()
< }
< }
<
< private fun doBackup(passphrase: String) {
< val export_methods = arrayOfNulls<String>(2)
< export_methods[0] = getString(R.string.export_to_clipboard)
< export_methods[1] = getString(R.string.export_to_email)
< MaterialAlertDialogBuilder(this@BalanceActivity)
< .setTitle(R.string.options_export)
< .setSingleChoiceItems(export_methods, 0, DialogInterface.OnClickListener { dialog, which ->
< try {
< PayloadUtil.getInstance(this@BalanceActivity).saveWalletToJSON(CharSequenceX(AccessFactory.getInstance(this@BalanceActivity).guid + AccessFactory.getInstance(this@BalanceActivity).pin))
< } catch (ioe: IOException) {
< } catch (je: JSONException) {
< } catch (de: DecryptionException) {
< } catch (mle: MnemonicLengthException) {
< }
< var encrypted: String? = null
< try {
< encrypted = AESUtil.encryptSHA256(PayloadUtil.getInstance(this@BalanceActivity).payload.toString(), CharSequenceX(passphrase))
< } catch (e: Exception) {
< Toast.makeText(this@BalanceActivity, e.message, Toast.LENGTH_SHORT).show()
< } finally {
< if (encrypted == null) {
< Toast.makeText(this@BalanceActivity, R.string.encryption_error, Toast.LENGTH_SHORT).show()
< return@OnClickListener
< }
< }
< val obj = PayloadUtil.getInstance(this@BalanceActivity).putPayload(encrypted, true)
< if (which == 0) {
< val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
< var clip: ClipData? = null
< clip = ClipData.newPlainText("Wallet backup", obj.toString())
< clipboard.setPrimaryClip(clip)
< Toast.makeText(this@BalanceActivity, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
< } else {
< val email = Intent(Intent.ACTION_SEND)
< email.putExtra(Intent.EXTRA_SUBJECT, "Ashigaru backup")
< email.putExtra(Intent.EXTRA_TEXT, obj.toString())
< email.type = "message/rfc822"
< startActivity(Intent.createChooser(email, getText(R.string.choose_email_client)))
< }
< dialog.dismiss()
< }
< ).show()
< }
<
< private fun doClipboardCheck() {
< val clipboard = this@BalanceActivity.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
< if (clipboard.hasPrimaryClip()) {
< val clip = clipboard.primaryClip
< val item = clip!!.getItemAt(0)
< if (item.text != null) {
< val text = item.text.toString()
< val s = text.split("\\s+").toTypedArray()
< try {
< for (i in s.indices) {
< val params = SamouraiWallet.getInstance().currentNetworkParams
< val privKeyReader = PrivKeyReader(s[i], params)
< if (privKeyReader.format != null &&
< (privKeyReader.format == PrivKeyReader.WIF_COMPRESSED || privKeyReader.format == PrivKeyReader.WIF_UNCOMPRESSED || privKeyReader.format == PrivKeyReader.BIP38 ||
< FormatsUtil.getInstance().isValidXprv(s[i]))
< ) {
< MaterialAlertDialogBuilder(this@BalanceActivity)
< .setTitle(R.string.app_name)
< .setMessage(R.string.privkey_clipboard)
< .setCancelable(false)
< .setPositiveButton(R.string.yes) { _, _ -> clipboard.setPrimaryClip(ClipData.newPlainText("", "")) }.setNegativeButton(R.string.no) { _, _ -> }.show()
< }
< }
< } catch (e: Exception) {
< }
< }
< }
< }
<
< private fun refreshTx(notifTx: Boolean, dragged: Boolean, launch: Boolean) {
< if (AppUtil.getInstance(this@BalanceActivity).isOfflineMode) {
< Toast.makeText(this@BalanceActivity, R.string.in_offline_mode, Toast.LENGTH_SHORT).show()
< /*
< CoordinatorLayout coordinatorLayout = new CoordinatorLayout(BalanceActivity.this);
< Snackbar snackbar = Snackbar.make(coordinatorLayout, R.string.in_offline_mode, Snackbar.LENGTH_LONG);
< snackbar.show();
< */
< }
<
< balanceViewModel.viewModelScope.launch {
< withContext(Dispatchers.IO) {
< async {
< WalletRefreshUtil.refreshWallet(
< notifTx = notifTx,
< launch = launch,
< context = applicationContext)
< }
< }
< }
< //
< // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
< // startForegroundService(intent);
< // } else {
< // startService(intent);
< // }
< }
<
< private fun doExplorerView(strHash: String?) {
< if (strHash != null) {
< val blockExplorer = BlockExplorerUtil.getInstance().getUri(true)
< val blockExplorerURL = PrefsUtil.getInstance(applicationContext).getValue(PrefsUtil.BLOCK_EXPLORER_URL, "") + "/tx/"
< val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(blockExplorerURL + strHash))
< startActivity(browserIntent)
< }
< }
<
< private fun txDetails(tx: Tx) {
< if (account == WhirlpoolMeta.getInstance(applicationContext).whirlpoolPostmix && tx.amount == 0.0) {
< return
< }
< val txIntent = Intent(this, TxDetailsActivity::class.java)
< txIntent.putExtra("TX", tx.toJSON().toString())
< txIntent.putExtra("_account", account)
< startActivity(txIntent)
< }
<
< private inner class RicochetQueueTask : AsyncTask<String?, Void?, String>() {
<
< override fun onPostExecute(result: String) {
< }
<
< override fun onPreExecute() {
< }
<
< override fun doInBackground(vararg params: String?): String {
< if (RicochetMeta.getInstance(this@BalanceActivity).queue.size > 0) {
< var count = 0
< val itr = RicochetMeta.getInstance(this@BalanceActivity).iterator
< while (itr.hasNext()) {
< if (count == 3) {
< break
< }
< try {
< val jObj = itr.next()
< val jHops = jObj.getJSONArray("hops")
< if (jHops.length() > 0) {
< val jHop = jHops.getJSONObject(jHops.length() - 1)
< val txHash = jHop.getString("hash")
< val txObj = APIFactory.getInstance(this@BalanceActivity).getTxInfo(txHash)
< if (txObj != null && txObj.has("block_height") && txObj.getInt("block_height") != -1) {
< itr.remove()
< count++
< }
< }
< } catch (je: JSONException) {
< }
< }
< }
< if (RicochetMeta.getInstance(this@BalanceActivity).staggered.size > 0) {
< var count = 0
< val staggered = RicochetMeta.getInstance(this@BalanceActivity).staggered
< val _staggered: MutableList<JSONObject> = ArrayList()
< for (jObj in staggered) {
< if (count == 3) {
< break
< }
< try {
< val jHops = jObj.getJSONArray("script")
< if (jHops.length() > 0) {
< val jHop = jHops.getJSONObject(jHops.length() - 1)
< val txHash = jHop.getString("tx")
< val txObj = APIFactory.getInstance(this@BalanceActivity).getTxInfo(txHash)
< if (txObj != null && txObj.has("block_height") && txObj.getInt("block_height") != -1) {
< count++
< } else {
< _staggered.add(jObj)
< }
< }
< } catch (je: JSONException) {
< } catch (cme: ConcurrentModificationException) {
< }
< }
< }
< return "OK"
< }
< }
<
< private fun doFeaturePayNymUpdate() {
< balanceViewModel.viewModelScope.launch(Dispatchers.IO) {
< if (PrefsUtil.getInstance(this@BalanceActivity).getValue(PrefsUtil.PAYNYM_CLAIMED, false) &&
< !PrefsUtil.getInstance(this@BalanceActivity).getValue(PrefsUtil.PAYNYM_FEATURED_SEGWIT, false)) {
< try {
< executeFeaturePayNymUpdate(this@BalanceActivity)
< Log.i(TAG, "executeFeaturePayNymUpdate: Feature update complete")
< } catch (e : Exception) {
< Log.i(TAG, "executeFeaturePayNymUpdate: Feature update Fail")
< }
< }
< }
< }
<
< private fun isFromPostmix() = intent.getBooleanExtra("come_from_postmix", false)
<
< companion object {
< private const val SCAN_COLD_STORAGE = 2011
< private const val SCAN_QR = 2012
< private const val UTXO_REQUESTCODE = 2012
< private const val TAG = "BalanceActivity"
< const val ACTION_INTENT = "com.samourai.wallet.BalanceFragment.REFRESH"
< const val DISPLAY_INTENT = "com.samourai.wallet.BalanceFragment.DISPLAY"
<
< public var appUpdateShowed : Boolean = false
< }
---
> package com.samourai.wallet.home
>
> import android.content.BroadcastReceiver
> import android.content.ClipData
> import android.content.ClipboardManager
> import android.content.Context
> import android.content.DialogInterface
> import android.content.Intent
> import android.content.IntentFilter
> import android.content.pm.ActivityInfo
> import android.graphics.BitmapFactory
> import android.graphics.Typeface
> import android.graphics.drawable.BitmapDrawable
> import android.net.Uri
> import android.os.AsyncTask
> import android.os.Bundle
> import android.os.Handler
> import android.util.Log
> import android.util.TypedValue
> import android.view.Menu
> import android.view.MenuItem
> import android.view.View
> import android.widget.EditText
> import android.widget.ImageView
> import android.widget.LinearLayout
> import android.widget.TextView
> import android.widget.Toast
> import androidx.activity.result.contract.ActivityResultContracts
> import androidx.activity.viewModels
> import androidx.appcompat.app.AlertDialog
> import androidx.core.content.ContextCompat
> import androidx.lifecycle.viewModelScope
> import androidx.localbroadcastmanager.content.LocalBroadcastManager
> import androidx.recyclerview.widget.LinearLayoutManager
> import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
> import androidx.transition.ChangeBounds
> import androidx.transition.TransitionManager
> import com.dm.zbar.android.scanner.ZBarConstants
> import com.google.android.material.dialog.MaterialAlertDialogBuilder
> import com.google.android.material.shape.ShapeAppearanceModel
> import com.google.gson.Gson
> import com.samourai.wallet.BuildConfig
> import com.samourai.wallet.R
> import com.samourai.wallet.ReceiveActivity
> import com.samourai.wallet.SamouraiActivity
> import com.samourai.wallet.SamouraiWallet
> import com.samourai.wallet.access.AccessFactory
> import com.samourai.wallet.api.APIFactory
> import com.samourai.wallet.api.APIFactory.TxMostRecentDateComparator
> import com.samourai.wallet.api.Tx
> import com.samourai.wallet.bip47.BIP47Meta
> import com.samourai.wallet.bip47.BIP47Util
> import com.samourai.wallet.bip47.paynym.WebUtil
> import com.samourai.wallet.cahoots.Cahoots
> import com.samourai.wallet.cahoots.psbt.PSBTUtil
> import com.samourai.wallet.collaborate.CollaborateActivity
> import com.samourai.wallet.constants.SamouraiAccountIndex.POSTMIX
> import com.samourai.wallet.crypto.AESUtil
> import com.samourai.wallet.crypto.DecryptionException
> import com.samourai.wallet.databinding.ActivityBalanceBinding
> import com.samourai.wallet.fragments.CameraFragmentBottomSheet
> import com.samourai.wallet.fragments.ScanFragment
> import com.samourai.wallet.hd.HD_WalletFactory
> import com.samourai.wallet.home.adapters.TxAdapter
> import com.samourai.wallet.network.NetworkDashboard
> import com.samourai.wallet.network.dojo.DojoUtil
> import com.samourai.wallet.pairing.PairingMenuActivity
> import com.samourai.wallet.payload.ExternalBackupManager.askPermission
> import com.samourai.wallet.payload.ExternalBackupManager.hasPermissions
> import com.samourai.wallet.payload.ExternalBackupManager.onActivityResult
> import com.samourai.wallet.payload.PayloadUtil
> import com.samourai.wallet.paynym.PayNymHome
> import com.samourai.wallet.paynym.api.PayNymApiService
> import com.samourai.wallet.paynym.fragments.PayNymOnBoardBottomSheet
> import com.samourai.wallet.paynym.models.NymResponse
> import com.samourai.wallet.ricochet.RicochetMeta
> import com.samourai.wallet.segwit.bech32.Bech32Util
> import com.samourai.wallet.send.BlockedUTXO
> import com.samourai.wallet.send.MyTransactionOutPoint
> import com.samourai.wallet.send.SendActivity
> import com.samourai.wallet.send.SendActivity.isPSBT
> import com.samourai.wallet.send.batch.BatchSpendActivity
> import com.samourai.wallet.send.batch.InputBatchSpendHelper.canParseAsBatchSpend
> import com.samourai.wallet.send.batch.InputBatchSpendHelper.canParseAsBatchSpend
> import com.samourai.wallet.send.cahoots.ManualCahootsActivity
> import com.samourai.wallet.service.WalletRefreshWorker
> import com.samourai.wallet.settings.SettingsActivity
> import com.samourai.wallet.stealth.StealthModeController
> import com.samourai.wallet.tools.ToolsBottomSheet
> import com.samourai.wallet.tools.viewmodels.Auth47ViewModel
> import com.samourai.wallet.tor.EnumTorState
> import com.samourai.wallet.tor.SamouraiTorManager
> import com.samourai.wallet.tor.TorState
> import com.samourai.wallet.tx.TxDetailsActivity
> import com.samourai.wallet.util.CharSequenceX
> import com.samourai.wallet.util.PrefsUtil
> import com.samourai.wallet.util.PrivKeyReader
> import com.samourai.wallet.util.TimeOutUtil
> import com.samourai.wallet.util.activity.ActivityHelper
> import com.samourai.wallet.util.func.FormatsUtil
> import com.samourai.wallet.util.func.MessageSignUtil
> import com.samourai.wallet.util.network.BlockExplorerUtil
> import com.samourai.wallet.util.tech.AppUtil
> import com.samourai.wallet.util.tech.LogUtil
> import com.samourai.wallet.util.tech.askNotificationPermission
> import com.samourai.wallet.utxos.UTXOSActivity
> import com.samourai.wallet.whirlpool.WhirlpoolHome
> import com.samourai.wallet.whirlpool.WhirlpoolMeta
> import com.samourai.wallet.whirlpool.service.WhirlpoolNotificationService
> import com.samourai.wallet.widgets.ItemDividerDecorator
> import com.samourai.wallet.widgets.popUpMenu.popupMenu
> import com.squareup.picasso.Callback
> import com.squareup.picasso.Picasso
> import io.reactivex.Observable
> import io.reactivex.Single
> import io.reactivex.android.schedulers.AndroidSchedulers
> import io.reactivex.schedulers.Schedulers
> import kotlinx.coroutines.Dispatchers
> import kotlinx.coroutines.delay
> import kotlinx.coroutines.launch
> import kotlinx.coroutines.withContext
> import org.bitcoinj.crypto.MnemonicException.MnemonicLengthException
> import org.bitcoinj.script.Script
> import org.bouncycastle.util.encoders.Hex
> import org.json.JSONException
> import org.json.JSONObject
> import java.io.IOException
> import java.util.Collections
>
>
> open class BalanceActivity : SamouraiActivity() {
> private var txs: MutableList<Tx>? = null
> private var ricochetQueueTask: RicochetQueueTask? = null
> private val balanceViewModel: BalanceViewModel by viewModels()
> private lateinit var binding: ActivityBalanceBinding
> private var menu: Menu? = null
> private val menuTorIcon: ImageView? = null
> private var executeQuitAppProcessStarted = false;
>
> private var receiver: BroadcastReceiver = object : BroadcastReceiver() {
> override fun onReceive(context: Context, intent: Intent) {
> if (ACTION_INTENT == intent.action) {
> if (binding.progressBar != null) {
> showProgress()
> }
> val notifTx = intent.getBooleanExtra("notifTx", false)
> val fetch = intent.getBooleanExtra("fetch", false)
> val rbfHash: String?
> val blkHash: String?
> rbfHash = if (intent.hasExtra("rbf")) {
> intent.getStringExtra("rbf")
> } else {
> null
> }
> blkHash = if (intent.hasExtra("hash")) {
> intent.getStringExtra("hash")
> } else {
> null
> }
> val handler = Handler()
> handler.post {
> refreshTx(notifTx, false, false)
> if (this@BalanceActivity != null) {
> if (rbfHash != null) {
> MaterialAlertDialogBuilder(this@BalanceActivity)
> .setTitle(R.string.app_name)
> .setMessage(rbfHash + "\n\n" + getString(R.string.rbf_incoming))
> .setCancelable(true)
> .setPositiveButton(R.string.yes, DialogInterface.OnClickListener { dialog, whichButton -> doExplorerView(rbfHash) })
> .setNegativeButton(R.string.no, object : DialogInterface.OnClickListener {
> override fun onClick(dialog: DialogInterface, whichButton: Int) {
> }
> }).show()
> }
> }
> }
> }
> }
> }
> private var receiverDisplay: BroadcastReceiver = object : BroadcastReceiver() {
> override fun onReceive(context: Context, intent: Intent) {
> if (DISPLAY_INTENT == intent.action) {
> updateDisplay(true)
> checkDust()
> }
> }
> }
>
> private fun checkDust() {
> balanceViewModel.viewModelScope.launch {
> withContext(Dispatchers.Default) {
> val utxos = APIFactory.getInstance(this@BalanceActivity).getUtxos(false)
> val utxoWarnings = arrayListOf<MyTransactionOutPoint>()
> for (utxo in utxos) {
> val outpoints = utxo.outpoints
> for (out in outpoints) {
> val scriptBytes = out.scriptBytes
> var address: String? = null
> try {
> address = if (Bech32Util.getInstance().isBech32Script(Hex.toHexString(scriptBytes))) {
> Bech32Util.getInstance().getAddressFromScript(Hex.toHexString(scriptBytes))
> } else {
> Script(scriptBytes).getToAddress(SamouraiWallet.getInstance().currentNetworkParams).toString()
> }
> } catch (e: Exception) {
> }
> val path = APIFactory.getInstance(this@BalanceActivity).unspentPaths[address]
> if (path != null && path.startsWith("M/1/")) {
> continue
> }
> val hash = out.hash.toString()
> val idx = out.txOutputN
> val amount = out.value.longValue()
> val contains = BlockedUTXO.getInstance().contains(hash, idx) || BlockedUTXO.getInstance().containsNotDusted(hash, idx)
> val containsInPostMix = BlockedUTXO.getInstance().containsPostMix(hash, idx) || BlockedUTXO.getInstance().containsNotDustedPostMix(hash, idx)
> if (amount < BlockedUTXO.BLOCKED_UTXO_THRESHOLD && !contains && !containsInPostMix) {
> utxoWarnings.add(out);
> // BalanceActivity.this.runOnUiThread(new Runnable() {
> // @Override
> }
> }
> }
> if(! utxoWarnings.isEmpty()) {
> withContext(Dispatchers.Main) {
> utxoWarnings.forEach {
> val hash = it.hash.toString()
> val idx = it.txOutputN
> val amount = it.value.longValue()
> var message: String? = this@BalanceActivity.getString(R.string.dusting_attempt)
> message += "\n\n"
> message += this@BalanceActivity.getString(R.string.dusting_attempt_amount)
> message += " "
> message += FormatsUtil.formatBTC(amount)
> message += this@BalanceActivity.getString(R.string.dusting_attempt_id)
> message += " "
> message += "$hash-$idx"
> val dlg = MaterialAlertDialogBuilder(this@BalanceActivity)
> .setTitle(R.string.dusting_tx)
> .setMessage(message)
> .setCancelable(false)
> .setPositiveButton(R.string.dusting_attempt_mark_unspendable) { dialog, whichButton ->
> if (account == WhirlpoolMeta.getInstance(this@BalanceActivity).whirlpoolPostmix) {
> BlockedUTXO.getInstance().addPostMix(hash, idx, amount)
> } else {
> BlockedUTXO.getInstance().add(hash, idx, amount)
> }
> saveState()
> }.setNegativeButton(R.string.dusting_attempt_ignore) { dialog, whichButton ->
> if (account == WhirlpoolMeta.getInstance(this@BalanceActivity).whirlpoolPostmix) {
> BlockedUTXO.getInstance().addNotDustedPostMix(hash, idx)
> } else {
> BlockedUTXO.getInstance().addNotDusted(hash, idx)
> }
> saveState()
> }
> if (!isFinishing) {
> dlg.show()
> }
> }
> }
> }
> }
> }
> }
>
> override fun onCreate(savedInstanceState: Bundle?) {
> //Switch themes based on accounts (blue theme for whirlpool account)
> setSwitchThemes(true)
> super.onCreate(savedInstanceState)
> binding = ActivityBalanceBinding.inflate(layoutInflater)
> setContentView(binding.root)
> balanceViewModel.setAccount(account)
> makePaynymAvatarCache()
> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
> setSupportActionBar(binding.toolbar)
> binding.rvTxes.layoutManager = LinearLayoutManager(this)
> val drawable = ContextCompat.getDrawable(this, R.drawable.divider_grey)
> binding.rvTxes.addItemDecoration(ItemDividerDecorator(drawable))
> txs = ArrayList()
> val is_sat_prefs = PrefsUtil.getInstance(this@BalanceActivity).getValue(PrefsUtil.IS_SAT, false)
> findViewById<View>(R.id.whirlpool_fab).setOnClickListener { view: View? ->
> val intent = Intent(this@BalanceActivity, WhirlpoolHome::class.java)
> startActivity(intent)
> binding.fabMenu.toggle(true)
> }
> binding.sendFab.setOnClickListener(View.OnClickListener { view: View? ->
>
> val isPostmixAccount = account == POSTMIX
>
> val activityType =
> if (isPostmixAccount) SendActivity::class.java
> else AccountSelectionActivity::class.java
>
> val intent = Intent(this@BalanceActivity, activityType)
> intent.putExtra("via_menu", true)
> if (isPostmixAccount) {
> intent.putExtra("_account", account)
> }
> startActivity(intent)
> binding.fabMenu.toggle(true)
> })
> var payload: JSONObject? = null
> payload = try {
> PayloadUtil.getInstance(this@BalanceActivity).payload
> } catch (e: Exception) {
> AppUtil.getInstance(applicationContext).restartApp()
> e.printStackTrace()
> return
> }
> if (account == 0 && payload != null && payload.has("prev_balance")) {
> try {
> setBalance(payload.getLong("prev_balance"), is_sat_prefs)
> } catch (e: Exception) {
> setBalance(0L, is_sat_prefs)
> }
> } else {
> setBalance(0L, is_sat_prefs)
> }
> binding.receiveFab.setOnClickListener { view: View? ->
> binding.fabMenu.toggle(true)
> val hdw = HD_WalletFactory.getInstance(this@BalanceActivity).get()
> if (hdw != null) {
> val intent = Intent(this@BalanceActivity, ReceiveActivity::class.java)
> startActivity(intent)
> }
> }
> binding.paynymFab.setOnClickListener { view: View? ->
> binding.fabMenu.toggle(true)
> val intent = Intent(this@BalanceActivity, PayNymHome::class.java)
> startActivity(intent)
> }
> binding.txSwipeContainer.setOnRefreshListener(OnRefreshListener {
> doClipboardCheck()
> refreshTx(false, true, false)
> binding.txSwipeContainer.isRefreshing = false
> showProgress()
> })
> val filter = IntentFilter(ACTION_INTENT)
> LocalBroadcastManager.getInstance(this@BalanceActivity).registerReceiver(receiver, filter)
> val filterDisplay = IntentFilter(DISPLAY_INTENT)
> LocalBroadcastManager.getInstance(this@BalanceActivity).registerReceiver(receiverDisplay, filterDisplay)
> if (PrefsUtil.getInstance(applicationContext).getValue(PrefsUtil.AUTO_BACKUP, true)) {
> if (!hasPermissions()) askPermission(this)
> }
> if (PrefsUtil.getInstance(this@BalanceActivity).getValue(PrefsUtil.PAYNYM_CLAIMED, false) && !PrefsUtil.getInstance(this@BalanceActivity).getValue(PrefsUtil.PAYNYM_FEATURED_SEGWIT, false)) {
> doFeaturePayNymUpdate()
> } else if (!PrefsUtil.getInstance(this@BalanceActivity).getValue(PrefsUtil.PAYNYM_CLAIMED, false) &&
> !PrefsUtil.getInstance(this@BalanceActivity).getValue(PrefsUtil.PAYNYM_REFUSED, false)
> ) {
> val payNymOnBoardBottomSheet = PayNymOnBoardBottomSheet()
> payNymOnBoardBottomSheet.show(supportFragmentManager, payNymOnBoardBottomSheet.tag)
> }
> if (RicochetMeta.getInstance(this@BalanceActivity).queue.size > 0) {
> if (ricochetQueueTask == null || ricochetQueueTask!!.status == AsyncTask.Status.FINISHED) {
> ricochetQueueTask = RicochetQueueTask()
> ricochetQueueTask!!.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR)
> }
> }
> if (!AppUtil.getInstance(this@BalanceActivity).isClipboardSeen) {
> doClipboardCheck()
> }
> setUpTor()
> initViewModel()
> showProgress()
> if (account == 0) {
> BIP47Util.getInstance(applicationContext)
> .payNymLogoLive.observe(this) {
> binding.toolbarIcon.setImageBitmap(it)
> }
> binding.toolbarIcon.setOnClickListener {
> showToolOptions(it)
> }
> val delayedHandler = Handler()
> delayedHandler.postDelayed({
> var notifTx = false
> val extras = intent.extras
> if (extras != null && extras.containsKey("notifTx")) {
> notifTx = extras.getBoolean("notifTx")
> }
> refreshTx(notifTx, false, true)
> updateDisplay(false)
> }, 100L)
> } else {
> binding.toolbarIcon.visibility = View.GONE
> binding.toolbar.setTitleMargin(0, 0, 0, 0)
> binding.toolbar.titleMarginEnd = -50
> binding.toolbar.setNavigationIcon(R.drawable.ic_baseline_arrow_back_24)
> binding.toolbar.setNavigationOnClickListener {
> super.onBackPressed()
> }
> binding.receiveFab.visibility = View.GONE
> binding.whirlpoolFab.visibility = View.GONE
> binding.paynymFab.visibility = View.GONE
> Handler().postDelayed({ updateDisplay(true) }, 600L)
> }
> balanceViewModel.loadOfflineData()
>
> updateDisplay(false)
> checkDeepLinks()
> doExternalBackUp()
> AppUtil.getInstance(applicationContext).walletLoading.observe(this) {
> if (it) {
> showProgress()
> } else {
> hideProgress()
> }
> }
> if (intent.getBooleanExtra("refresh", false)) {
> balanceViewModel.viewModelScope.launch {
> withContext(Dispatchers.Default) {
> delay(800)
> WalletRefreshWorker.enqueue(applicationContext, notifTx = false, launched = false)
> }
> }
> }
>
> balanceViewModel.viewModelScope.launch {
> withContext(Dispatchers.Main) {
> askNotificationPermission(this@BalanceActivity)
> }
> }
> }
>
> private fun showToolOptions(it: View) {
> val bitmapImage = BIP47Util.getInstance(applicationContext).payNymLogoLive.value
> var drawable = ContextCompat.getDrawable(this, R.drawable.ic_samourai_logo)
> var nym = PrefsUtil.getInstance(applicationContext)
> .getValue(PrefsUtil.PAYNYM_BOT_NAME, BIP47Meta.getInstance().getDisplayLabel(BIP47Util.getInstance(applicationContext).paymentCode.toString()))
> if (bitmapImage != null) {
> drawable = BitmapDrawable(resources, bitmapImage)
> }
> if (nym.isNullOrEmpty()) {
> nym = BIP47Meta.getInstance().getDisplayLabel(BIP47Util.getInstance(applicationContext).paymentCode.toString())
> }
> val toolWindowSize = applicationContext.resources.displayMetrics.density * 220;
> val popupMenu = popupMenu {
> fixedContentWidthInPx = toolWindowSize.toInt()
> style = R.style.Theme_Samourai_Widget_MPM_Menu_Dark
> section {
> item {
> label = nym
> iconDrawable = drawable
> iconSize = 34
> labelColor = ContextCompat.getColor(applicationContext, R.color.white)
> disableTint = true
> iconShapeAppearanceModel = ShapeAppearanceModel().toBuilder()
> .setAllCornerSizes(resources.getDimension(R.dimen.qr_image_corner_radius))
> .build()
> callback = {
> val intent = Intent(this@BalanceActivity, PayNymHome::class.java)
> startActivity(intent)
> }
> }
> item {
> label = "Collaborate"
> iconSize = 18
> callback = {
> val intent = Intent(this@BalanceActivity, CollaborateActivity::class.java)
> startActivity(intent)
> }
> icon = R.drawable.ic_connect_without_contact
> }
> item {
> label = "Tools"
> icon = R.drawable.ic_tools
> iconSize = 18
> hasNestedItems
> callback = {
> ToolsBottomSheet.showTools(supportFragmentManager)
> }
> }
> }
> section {
> item {
> label = "Pairing"
> icon = R.drawable.pairing_icon
> iconSize = 18
> hasNestedItems
> callback = {
> val intent = Intent(this@BalanceActivity, PairingMenuActivity::class.java)
> startActivity(intent)
> }
> }
> item {
> label = getString(R.string.action_settings)
> icon = R.drawable.ic_cog
> iconSize = 18
> callback = {
> TimeOutUtil.getInstance().updatePin()
> val intent = Intent(this@BalanceActivity, SettingsActivity::class.java)
> startActivity(intent)
> }
> }
> item {
> label = "Exit Wallet"
> iconSize = 18
> iconColor = ContextCompat.getColor(this@BalanceActivity, R.color.mpm_red)
> labelColor = ContextCompat.getColor(this@BalanceActivity, R.color.mpm_red)
> icon = R.drawable.ic_baseline_power_settings_new_24
> callback = {
> this@BalanceActivity.onBackPressed()
> }
> }
> }
> }
> popupMenu.show(this@BalanceActivity, it)
> }
>
> private fun hideProgress() {
> binding.progressBar.hide()
> }
>
> private fun showProgress() {
> binding.progressBar.isIndeterminate = true
> binding.progressBar.show()
> }
>
> private fun checkDeepLinks() {
> val bundle = intent.extras ?: return
> if (bundle.containsKey("pcode") || bundle.containsKey("uri") || bundle.containsKey("amount")) {
> if (bundle.containsKey("uri")) {
> if (bundle.getString("uri")?.startsWith("auth47") == true) {
> ToolsBottomSheet.showTools(supportFragmentManager, ToolsBottomSheet.ToolType.AUTH47,
> bundle = Bundle().apply {
> putString("KEY", bundle.getString("uri"))
> })
> return;
> }
> }
> if (balanceViewModel.balance.value != null) bundle.putLong("balance", balanceViewModel.balance.value!!)
> val intent = Intent(this, AccountSelectionActivity::class.java)
> intent.putExtra("_account", account)
> intent.putExtras(bundle)
> startActivity(intent)
> }
> }
>
> override fun onNewIntent(intent: Intent) {
> super.onNewIntent(intent)
> setIntent(intent)
> }
>
> private fun initViewModel() {
> val adapter = TxAdapter(applicationContext, ArrayList(), account)
> adapter.setClickListener { position: Int, tx: Tx -> txDetails(tx) }
> binding.rvTxes.adapter = adapter
> val is_sat_prefs = PrefsUtil.getInstance(this@BalanceActivity).getValue(PrefsUtil.IS_SAT, false)
> balanceViewModel.balance.observe(this) { balance: Long? ->
> if (balance == null) {
> return@observe
> }
> if (balance < 0) {
> return@observe
> }
> if (binding.progressBar.visibility == View.VISIBLE && balance <= 0) {
> return@observe
> }
> setBalance(balance, is_sat_prefs)
> }
> adapter.setTxes(balanceViewModel.txs.value)
> setBalance(balanceViewModel.balance.value, is_sat_prefs)
> balanceViewModel.satState.observe(this) { state: Boolean? ->
> var isSats = false
> if (state != null) {
> isSats = state
> }
> setBalance(balanceViewModel.balance.value, isSats)
> adapter.notifyDataSetChanged()
> }
> balanceViewModel.txs.observe(this) { list -> adapter.setTxes(list) }
> binding.toolbarLayout.setOnClickListener { v: View? ->
> val is_sat = balanceViewModel!!.toggleSat()
> PrefsUtil.getInstance(this@BalanceActivity).setValue(PrefsUtil.IS_SAT, is_sat)
> }
> binding.toolbarLayout.setOnLongClickListener {
> val intent = Intent(this@BalanceActivity, UTXOSActivity::class.java)
> intent.putExtra("_account", account)
> startActivityForResult(intent, UTXO_REQUESTCODE)
> false
> }
> }
>
> private fun setBalance(balance: Long?, isSat: Boolean) {
> if (balance == null) {
> return
> }
> if (supportActionBar != null) {
> TransitionManager.beginDelayedTransition(binding.toolbarLayout, ChangeBounds())
> val displayAmount = if (isSat) FormatsUtil.formatSats(balance) else FormatsUtil.formatBTC(balance)
> binding.toolbar.title = displayAmount
> title = displayAmount
> binding.toolbarLayout.title = displayAmount
> }
> }
>
> public override fun onResume() {
> super.onResume()
> executeQuitAppProcessStarted = false;
>
> // IntentFilter filter = new IntentFilter(ACTION_INTENT);
> // LocalBroadcastManager.getInstance(BalanceActivity.this).registerReceiver(receiver, filter);
> AppUtil.getInstance(this@BalanceActivity).checkTimeOut()
> try {
> val isSatPrefs = PrefsUtil.getInstance(applicationContext).getValue(PrefsUtil.IS_SAT, false)
> if (isSatPrefs != balanceViewModel.satState.value) {
> balanceViewModel.toggleSat()
> }
> } catch (e: Exception) {
> LogUtil.error(TAG, e)
> }
> //
> // Intent intent = new Intent("com.samourai.wallet.MainActivity2.RESTART_SERVICE");
> // LocalBroadcastManager.getInstance(BalanceActivity.this).sendBroadcast(intent);
> }
>
> fun createTag(text: String?): View {
> val scale = resources.displayMetrics.density
> val lparams = LinearLayout.LayoutParams(
> LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT
> )
> val textView = TextView(applicationContext)
> textView.text = text
> textView.setTextColor(ContextCompat.getColor(applicationContext, R.color.white))
> textView.layoutParams = lparams
> textView.setBackgroundResource(R.drawable.tag_round_shape)
> textView.setPadding((8 * scale + 0.5f).toInt(), (6 * scale + 0.5f).toInt(), (8 * scale + 0.5f).toInt(), (6 * scale + 0.5f).toInt())
> textView.typeface = Typeface.DEFAULT_BOLD
> textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 11f)
> return textView
> }
>
> private fun makePaynymAvatarCache() {
> try {
> val paymentCodes = ArrayList(BIP47Meta.getInstance().getSortedByLabels(false, true))
> if (PrefsUtil.getInstance(applicationContext).getValue(PrefsUtil.PAYNYM_BOT_NAME, "").isNullOrEmpty()
> && PrefsUtil.getInstance(applicationContext).getValue(PrefsUtil.PAYNYM_CLAIMED,false)) {
> val strPaymentCode = BIP47Util.getInstance(application).paymentCode.toString()
> val apiService = PayNymApiService.getInstance(strPaymentCode, getApplication());
> balanceViewModel.viewModelScope.launch {
> withContext(Dispatchers.IO) {
> try {
> val response = apiService.getNymInfo()
> if (response.isSuccessful) {
> val responseJson = response.body?.string()
> if (responseJson != null) {
> val jsonObject = JSONObject(responseJson)
> val nym = Gson().fromJson(jsonObject.toString(), NymResponse::class.java);
> PrefsUtil.getInstance(applicationContext).setValue(PrefsUtil.PAYNYM_BOT_NAME, nym.nymName)
>
> } else
> throw Exception("Invalid response ")
> }
> } catch (_: Exception) {
>
> }
> }
> }
> }
> if (!BIP47Util.getInstance(applicationContext).avatarImage().exists()) {
> BIP47Util.getInstance(applicationContext).fetchBotImage()
> .subscribe()
> .apply {
> registerDisposable(this)
> balanceViewModel.viewModelScope.launch {
> withContext(Dispatchers.Default) {
> val bitmap = BitmapFactory.decodeFile(BIP47Util.getInstance(applicationContext).avatarImage().path)
> BIP47Util.getInstance(applicationContext)
> .setAvatar(bitmap)
> }
> }
> }
> }
> balanceViewModel.viewModelScope.launch {
> withContext(Dispatchers.Default) {
> if (BIP47Util.getInstance(applicationContext).avatarImage().exists()) {
> val bitmap = BitmapFactory.decodeFile(BIP47Util.getInstance(applicationContext).avatarImage().path)
> BIP47Util.getInstance(applicationContext)
> .setAvatar(bitmap)
> }
> }
> }
> for (code in paymentCodes) {
> Picasso.get()
> .load(WebUtil.PAYNYM_API + code + "/avatar").fetch(object : Callback {
> override fun onSuccess() {
> /*NO OP*/
> }
>
> override fun onError(e: Exception) {
> /*NO OP*/
> }
> })
> }
> } catch (ignored: Exception) {
> }
> }
>
> public override fun onDestroy() {
> LocalBroadcastManager.getInstance(this@BalanceActivity).unregisterReceiver(receiver)
> LocalBroadcastManager.getInstance(this@BalanceActivity).unregisterReceiver(receiverDisplay)
>
> if (PrefsUtil.getInstance(this.application).getValue(StealthModeController.PREF_ENABLED, false)) {
> StealthModeController.enableStealth(applicationContext)
> }
> super.onDestroy()
> }
>
> override fun onCreateOptionsMenu(menu: Menu): Boolean {
> menuInflater.inflate(R.menu.main, menu)
> if (BuildConfig.FLAVOR == "staging") menu.findItem(R.id.action_mock_fees).isVisible = true
> menu.findItem(R.id.action_refresh).isVisible = false
> menu.findItem(R.id.action_share_receive).isVisible = false
> menu.findItem(R.id.action_ricochet).isVisible = false
> menu.findItem(R.id.action_empty_ricochet).isVisible = false
> menu.findItem(R.id.action_sign).isVisible = false
> menu.findItem(R.id.action_fees).isVisible = false
> menu.findItem(R.id.action_batch).isVisible = false
> WhirlpoolMeta.getInstance(applicationContext)
> if (account == WhirlpoolMeta.getInstance(applicationContext).whirlpoolPostmix) {
> menu.findItem(R.id.action_backup).isVisible = false
> menu.findItem(R.id.action_network_dashboard).isVisible = false
> menu.findItem(R.id.action_postmix_balance).isVisible = false
> val item = menu.findItem(R.id.action_menu_account)
> item.actionView = createTag(" POST-MIX ")
> item.isVisible = true
> item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
> }
> this.menu = menu
> return super.onCreateOptionsMenu(menu)
> }
>
> override fun onOptionsItemSelected(item: MenuItem): Boolean {
> // Handle action bar item clicks here. The action bar will
> // automatically handle clicks on the Home/Up button, so long
> // as you specify a parent activity in AndroidManifest.xml.
> val id = item.itemId
> if (id == android.R.id.home) {
> finish()
> return super.onOptionsItemSelected(item)
> }
> if (id == R.id.action_mock_fees) {
> SamouraiWallet.MOCK_FEE = !SamouraiWallet.MOCK_FEE
> refreshTx(false, true, false)
> binding.txSwipeContainer.isRefreshing = false
> showProgress()
> return super.onOptionsItemSelected(item)
> }
> if (id == R.id.action_postmix_balance) {
> startActivity(Intent(this, BalanceActivity::class.java).apply {
> putExtra("_account", POSTMIX)
> })
> return super.onOptionsItemSelected(item)
> }
>
> // noinspection SimplifiableIfStatement
> if (id == R.id.action_network_dashboard) {
> startActivity(Intent(this, NetworkDashboard::class.java))
> } // noinspection SimplifiableIfStatement
> if (id == R.id.action_support) {
> ActivityHelper.launchSupportPageInBrowser(this, SamouraiTorManager.isConnected())
> } else if (id == R.id.action_utxo) {
> doUTXO()
> } else if (id == R.id.action_backup) {
> if (SamouraiWallet.getInstance().hasPassphrase(this@BalanceActivity)) {
> if (HD_WalletFactory.getInstance(this@BalanceActivity).get() != null && SamouraiWallet.getInstance().hasPassphrase(this@BalanceActivity)) {
> doBackup(HD_WalletFactory.getInstance(this@BalanceActivity).get().passphrase)
> }
> } else {
> val builder = MaterialAlertDialogBuilder(this)
> builder.setTitle(R.string.enter_backup_password)
> val view = layoutInflater.inflate(R.layout.password_input_dialog_layout, null)
> val password = view.findViewById<EditText>(R.id.restore_dialog_password_edittext)
> val message = view.findViewById<TextView>(R.id.dialogMessage)
> message.setText(R.string.backup_password)
> builder.setPositiveButton(R.string.confirm) { dialog: DialogInterface, which: Int ->
> val pw = password.text.toString()
> if (pw.length >= AppUtil.MIN_BACKUP_PW_LENGTH && pw.length <= AppUtil.MAX_BACKUP_PW_LENGTH) {
> doBackup(pw)
> } else {
> Toast.makeText(applicationContext, R.string.password_error, Toast.LENGTH_SHORT).show()
> }
> dialog.dismiss()
> }
> builder.setNegativeButton(R.string.cancel) { dialog: DialogInterface, which: Int -> dialog.dismiss() }
> builder.setView(view)
> builder.show()
> }
> } else if (id == R.id.action_scan_qr) {
> doScan()
> } else {
> }
> return super.onOptionsItemSelected(item)
> }
>
> private fun setUpTor() {
> SamouraiTorManager.getTorStateLiveData().observe(this) { torState: TorState ->
> if (torState.state == EnumTorState.ON) {
> PrefsUtil.getInstance(this).setValue(PrefsUtil.ENABLE_TOR, true)
> binding.progressBar.visibility = View.INVISIBLE
> menuTorIcon?.setImageResource(R.drawable.tor_on)
> } else if (torState.state == EnumTorState.STARTING) {
> binding.progressBar.visibility = View.VISIBLE
> menuTorIcon?.setImageResource(R.drawable.tor_on)
> } else {
> if (torState.state == EnumTorState.OFF && !executeQuitAppProcessStarted) {
> PrefsUtil.getInstance(this).setValue(PrefsUtil.ENABLE_TOR, false)
> }
> binding.progressBar.visibility = View.INVISIBLE
> menuTorIcon?.setImageResource(R.drawable.tor_off)
> }
> }
> }
>
> public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
> super.onActivityResult(requestCode, resultCode, data)
> onActivityResult(requestCode, resultCode, data, application)
> if (resultCode == RESULT_OK && requestCode == SCAN_COLD_STORAGE) {
> if (data?.getStringExtra(ZBarConstants.SCAN_RESULT) != null) {
> val strResult = data.getStringExtra(ZBarConstants.SCAN_RESULT)
> doPrivKey(strResult)
> }
> } else if (resultCode == RESULT_CANCELED && requestCode == SCAN_COLD_STORAGE) {
> } else if (resultCode == RESULT_OK && requestCode == SCAN_QR) {
>
> if (data?.getStringExtra(ZBarConstants.SCAN_RESULT) != null) {
> val strResult = data.getStringExtra(ZBarConstants.SCAN_RESULT)
> val params = SamouraiWallet.getInstance().currentNetworkParams
> val privKeyReader = PrivKeyReader(strResult, params)
> try {
> if (privKeyReader.format != null) {
> doPrivKey(strResult!!.trim { it <= ' ' })
> } else if (strResult?.lowercase()?.startsWith(Auth47ViewModel.AUTH_SCHEME.lowercase()) == true) {
> ToolsBottomSheet.showTools(supportFragmentManager, ToolsBottomSheet.ToolType.AUTH47,
> bundle = Bundle().apply {
> putString("KEY", strResult)
> })
> } else if (Cahoots.isCahoots(strResult!!.trim { it <= ' ' })) {
> val cahootIntent = ManualCahootsActivity.createIntentResume(this, account, strResult.trim { it <= ' ' })
> startActivity(cahootIntent)
> } else if (isPSBT(strResult.trim { it <= ' ' })) {
> PSBTUtil.getInstance(this@BalanceActivity).doPSBT(strResult.trim { it <= ' ' })
> } else if (DojoUtil.getInstance(this@BalanceActivity).isValidPairingPayload(strResult.trim { it <= ' ' })) {
> val intent = Intent(this@BalanceActivity, NetworkDashboard::class.java)
> intent.putExtra("params", strResult.trim { it <= ' ' })
> startActivity(intent)
> } else {
> val intent = Intent(this@BalanceActivity, AccountSelectionActivity::class.java)
> intent.putExtra("uri", strResult.trim { it <= ' ' })
> intent.putExtra("_account", account)
> startActivity(intent)
> }
> } catch (e: Exception) {
> }
> }
> }
> if (resultCode == RESULT_OK && requestCode == UTXO_REQUESTCODE) {
> refreshTx(false, false, false)
> showProgress()
> } else {
> }
> }
>
> override fun onBackPressed() {
> if (account == 0) {
> val builder = MaterialAlertDialogBuilder(this)
> builder.setMessage(R.string.ask_you_sure_exit)
> val alert = builder.create()
> alert.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.yes)) { dialog: DialogInterface?, id: Int ->
> executeQuitAppProcesses()
> }
> alert.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.no)) { dialog: DialogInterface, id: Int -> dialog.dismiss() }
> alert.show()
> } else {
> super.onBackPressed()
> }
> }
>
> private fun doExternalBackUp() {
> try {
> if (hasPermissions() && PrefsUtil.getInstance(application).getValue(PrefsUtil.AUTO_BACKUP, false)) {
> val disposable = Observable.fromCallable {
> PayloadUtil.getInstance(this@BalanceActivity).saveWalletToJSON(CharSequenceX(AccessFactory.getInstance(this@BalanceActivity).guid + AccessFactory.getInstance(this@BalanceActivity).pin))
> true
> }.subscribeOn(Schedulers.io())
> .observeOn(AndroidSchedulers.mainThread()).subscribe({ t: Boolean? -> }) { throwable: Throwable? -> LogUtil.error(TAG, throwable) }
> registerDisposable(disposable)
> }
> } catch (exception: Exception) {
> LogUtil.error(TAG, exception)
> }
> }
>
> private fun executeQuitAppProcesses() {
>
> executeQuitAppProcessStarted = true;
>
> try {
> if (hasPermissions() &&
> PrefsUtil.getInstance(application).getValue(PrefsUtil.AUTO_BACKUP, false)) {
>
> val disposable = Observable.fromCallable {
> PayloadUtil.getInstance(this@BalanceActivity)
> .saveWalletToJSON(CharSequenceX(
> AccessFactory.getInstance(this@BalanceActivity).guid +
> AccessFactory.getInstance(this@BalanceActivity).pin))
> true
> }.subscribeOn(Schedulers.io())
> .observeOn(AndroidSchedulers.mainThread())
> .subscribe({ t: Boolean? ->
> stopingServices()
> }) { throwable: Throwable? ->
> LogUtil.error(TAG, throwable)
> stopingServices()
> }
> registerDisposable(disposable)
> } else {
> stopingServices()
> }
> } catch (exception: Exception) {
> LogUtil.error(TAG, exception)
> stopingServices()
> }
> }
>
> private fun stopingServices() {
> if (SamouraiTorManager.isConnected()) {
> SamouraiTorManager.stop()
> }
> if (WhirlpoolNotificationService.isRunning(applicationContext)) {
> WhirlpoolNotificationService.stopService(applicationContext)
> }
> TimeOutUtil.getInstance().reset()
> if (StealthModeController.isStealthEnabled(applicationContext)) {
> StealthModeController.enableStealth(applicationContext)
> }
> // disconnect Whirlpool on app back key exit
> finishAffinity()
> finish()
> super.onBackPressed()
> }
>
> private fun updateDisplay(fromRefreshService: Boolean) {
> val txDisposable = loadTxes(account)
> .subscribeOn(Schedulers.io())
> .observeOn(AndroidSchedulers.mainThread())
> .subscribe { txes: List<Tx>?, throwable: Throwable? ->
> throwable?.printStackTrace()
> if (txes != null) {
> if (txes.isNotEmpty()) {
> balanceViewModel.setTx(txes)
> } else {
> if (balanceViewModel.txs.value != null && balanceViewModel.txs.value!!.size == 0) {
> balanceViewModel.setTx(txes)
> }
> }
> Collections.sort(txes, TxMostRecentDateComparator())
> txs!!.clear()
> txs!!.addAll(txes)
> }
> if (binding.progressBar.visibility == View.VISIBLE && fromRefreshService) {
> hideProgress()
> }
> }
> val balanceDisposable = loadBalance(account)
> .subscribeOn(Schedulers.io())
> .observeOn(AndroidSchedulers.mainThread())
> .subscribe { balance: Long?, throwable: Throwable? ->
> throwable?.printStackTrace()
> if (balanceViewModel.balance.value != null) {
> balanceViewModel.setBalance(balance)
> } else {
> balanceViewModel.setBalance(balance)
> }
> }
> registerDisposable(balanceDisposable)
> registerDisposable(txDisposable)
> // displayBalance();
> // txAdapter.notifyDataSetChanged();
> }
>
> private fun loadTxes(account: Int): Single<List<Tx>> {
> return Single.fromCallable {
> var loadedTxes: List<Tx> = ArrayList()
> if (account == 0) {
> loadedTxes = APIFactory.getInstance(this@BalanceActivity).allXpubTxs
> } else if (account == WhirlpoolMeta.getInstance(applicationContext).whirlpoolPostmix) {
> loadedTxes = APIFactory.getInstance(this@BalanceActivity).allPostMixTxs
> }
> loadedTxes
> }
> }
>
> private fun loadBalance(account: Int): Single<Long> {
> return Single.fromCallable {
> var loadedBalance = 0L
> if (account == 0) {
> loadedBalance = APIFactory.getInstance(this@BalanceActivity).xpubBalance
> } else if (account == WhirlpoolMeta.getInstance(applicationContext).whirlpoolPostmix) {
> loadedBalance = APIFactory.getInstance(this@BalanceActivity).xpubPostMixBalance
> }
> loadedBalance
> }
> }
>
> private fun doSettings() {
> TimeOutUtil.getInstance().updatePin()
> val intent = Intent(this@BalanceActivity, SettingsActivity::class.java)
> startActivity(intent)
> }
>
> var utxoListResult = registerForActivityResult(
> ActivityResultContracts.StartActivityForResult()
> ) {
> run {
> refreshTx(false, false, false)
> showProgress()
> }
> }
>
> private fun doUTXO() {
> val intent = Intent(this@BalanceActivity, UTXOSActivity::class.java)
> intent.putExtra("_account", account)
> utxoListResult.launch(intent)
> }
>
> private fun doScan() {
> val cameraFragmentBottomSheet = ScanFragment()
> cameraFragmentBottomSheet.show(supportFragmentManager, cameraFragmentBottomSheet.tag)
> cameraFragmentBottomSheet.setOnScanListener { code ->
> cameraFragmentBottomSheet.dismissAllowingStateLoss()
> val params = SamouraiWallet.getInstance().currentNetworkParams
> val privKeyReader = PrivKeyReader(code, params)
> try {
> when {
> canParseAsBatchSpend(code) -> {
> launchBatchSpend(code)
> }
> privKeyReader.format != null -> {
> doPrivKey(code.trim { it <= ' ' })
> }
> code.lowercase().startsWith(Auth47ViewModel.AUTH_SCHEME) -> {
> ToolsBottomSheet.showTools(supportFragmentManager, ToolsBottomSheet.ToolType.AUTH47,
> bundle = Bundle().apply {
> putString("KEY", code)
> })
> }
> Cahoots.isCahoots(code.trim { it <= ' ' }) -> {
> val cahootIntent = ManualCahootsActivity.createIntentResume(this, account, code.trim { it <= ' ' })
> startActivity(cahootIntent)
> }
> isPSBT(code.trim { it <= ' ' }) -> {
> ToolsBottomSheet.showTools(supportFragmentManager, ToolsBottomSheet.ToolType.PSBT,
> bundle = Bundle().apply {
> putString("KEY", code)
> })
> }
> DojoUtil.getInstance(this@BalanceActivity).isValidPairingPayload(code.trim { it <= ' ' }) -> {
> val intent = Intent(this@BalanceActivity, NetworkDashboard::class.java)
> intent.putExtra("params", code.trim { it <= ' ' })
> startActivity(intent)
> }
> else -> {
>
> val isPostmixAccount = account == POSTMIX
>
> val activityType =
> if (isPostmixAccount) SendActivity::class.java
> else AccountSelectionActivity::class.java
>
> val intent = Intent(this@BalanceActivity, activityType)
> intent.putExtra("uri", code.trim { it <= ' ' })
> if (isPostmixAccount) {
> intent.putExtra("_account", account)
> }
> startActivity(intent)
> }
> }
> } catch (e: Exception) {
> }
> }
> }
>
> private fun launchBatchSpend(inputBatchSpendAsJson: String) {
> val intent = Intent(this@BalanceActivity, AccountSelectionActivity::class.java)
> intent.putExtra("inputBatchSpend", inputBatchSpendAsJson)
> startActivity(intent)
> }
>
> private fun doSweepViaScan() {
> val cameraFragmentBottomSheet = CameraFragmentBottomSheet()
> cameraFragmentBottomSheet.show(supportFragmentManager, cameraFragmentBottomSheet.tag)
> cameraFragmentBottomSheet.setQrCodeScanListener { code: String ->
> cameraFragmentBottomSheet.dismissAllowingStateLoss()
> val params = SamouraiWallet.getInstance().currentNetworkParams
> val privKeyReader = PrivKeyReader(code, params)
> try {
> when {
> privKeyReader.format != null -> {
> doPrivKey(code.trim { it <= ' ' })
> }
> Cahoots.isCahoots(code.trim { it <= ' ' }) -> {
> val cahootIntent = ManualCahootsActivity.createIntentResume(this, account, code.trim { it <= ' ' })
> startActivity(cahootIntent)
> }
> isPSBT(code.trim { it <= ' ' }) -> {
> PSBTUtil.getInstance(this@BalanceActivity).doPSBT(code.trim { it <= ' ' })
> }
> DojoUtil.getInstance(this@BalanceActivity).isValidPairingPayload(code.trim { it <= ' ' }) -> {
> Toast.makeText(this@BalanceActivity, "Samourai Dojo full node coming soon.", Toast.LENGTH_SHORT).show()
> }
> else -> {
> val intent = Intent(this@BalanceActivity, AccountSelectionActivity::class.java)
> intent.putExtra("uri", code.trim { it <= ' ' })
> intent.putExtra("_account", account)
> startActivity(intent)
> }
> }
> } catch (e: Exception) {
> }
> }
> }
>
> private fun doPrivKey(data: String?) {
>
> val params = SamouraiWallet.getInstance().currentNetworkParams
> var privKeyReader: PrivKeyReader? = null
> var format: String? = null
> try {
> privKeyReader = PrivKeyReader(data, params)
> format = privKeyReader.format
> } catch (e: Exception) {
> Toast.makeText(this@BalanceActivity, e.message, Toast.LENGTH_SHORT).show()
> return
> }
> if (format != null) {
> ToolsBottomSheet.showTools(supportFragmentManager, ToolsBottomSheet.ToolType.SWEEP,
> bundle = Bundle().apply {
> putString("KEY", data)
> })
> } else {
> Toast.makeText(this@BalanceActivity, R.string.cannot_recognize_privkey, Toast.LENGTH_SHORT).show()
> }
> }
>
> private fun doBackup(passphrase: String) {
> val export_methods = arrayOfNulls<String>(2)
> export_methods[0] = getString(R.string.export_to_clipboard)
> export_methods[1] = getString(R.string.export_to_email)
> MaterialAlertDialogBuilder(this@BalanceActivity)
> .setTitle(R.string.options_export)
> .setSingleChoiceItems(export_methods, 0, DialogInterface.OnClickListener { dialog, which ->
> try {
> PayloadUtil.getInstance(this@BalanceActivity).saveWalletToJSON(CharSequenceX(AccessFactory.getInstance(this@BalanceActivity).guid + AccessFactory.getInstance(this@BalanceActivity).pin))
> } catch (ioe: IOException) {
> } catch (je: JSONException) {
> } catch (de: DecryptionException) {
> } catch (mle: MnemonicLengthException) {
> }
> var encrypted: String? = null
> try {
> encrypted = AESUtil.encryptSHA256(PayloadUtil.getInstance(this@BalanceActivity).payload.toString(), CharSequenceX(passphrase))
> } catch (e: Exception) {
> Toast.makeText(this@BalanceActivity, e.message, Toast.LENGTH_SHORT).show()
> } finally {
> if (encrypted == null) {
> Toast.makeText(this@BalanceActivity, R.string.encryption_error, Toast.LENGTH_SHORT).show()
> return@OnClickListener
> }
> }
> val obj = PayloadUtil.getInstance(this@BalanceActivity).putPayload(encrypted, true)
> if (which == 0) {
> val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
> var clip: ClipData? = null
> clip = ClipData.newPlainText("Wallet backup", obj.toString())
> clipboard.setPrimaryClip(clip)
> Toast.makeText(this@BalanceActivity, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
> } else {
> val email = Intent(Intent.ACTION_SEND)
> email.putExtra(Intent.EXTRA_SUBJECT, "Samourai Wallet backup")
> email.putExtra(Intent.EXTRA_TEXT, obj.toString())
> email.type = "message/rfc822"
> startActivity(Intent.createChooser(email, getText(R.string.choose_email_client)))
> }
> dialog.dismiss()
> }
> ).show()
> }
>
> private fun doClipboardCheck() {
> val clipboard = this@BalanceActivity.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
> if (clipboard.hasPrimaryClip()) {
> val clip = clipboard.primaryClip
> val item = clip!!.getItemAt(0)
> if (item.text != null) {
> val text = item.text.toString()
> val s = text.split("\\s+").toTypedArray()
> try {
> for (i in s.indices) {
> val params = SamouraiWallet.getInstance().currentNetworkParams
> val privKeyReader = PrivKeyReader(s[i], params)
> if (privKeyReader.format != null &&
> (privKeyReader.format == PrivKeyReader.WIF_COMPRESSED || privKeyReader.format == PrivKeyReader.WIF_UNCOMPRESSED || privKeyReader.format == PrivKeyReader.BIP38 ||
> FormatsUtil.getInstance().isValidXprv(s[i]))
> ) {
> MaterialAlertDialogBuilder(this@BalanceActivity)
> .setTitle(R.string.app_name)
> .setMessage(R.string.privkey_clipboard)
> .setCancelable(false)
> .setPositiveButton(R.string.yes) { _, _ -> clipboard.setPrimaryClip(ClipData.newPlainText("", "")) }.setNegativeButton(R.string.no) { _, _ -> }.show()
> }
> }
> } catch (e: Exception) {
> }
> }
> }
> }
>
> private fun refreshTx(notifTx: Boolean, dragged: Boolean, launch: Boolean) {
> if (AppUtil.getInstance(this@BalanceActivity).isOfflineMode) {
> Toast.makeText(this@BalanceActivity, R.string.in_offline_mode, Toast.LENGTH_SHORT).show()
> /*
> CoordinatorLayout coordinatorLayout = new CoordinatorLayout(BalanceActivity.this);
> Snackbar snackbar = Snackbar.make(coordinatorLayout, R.string.in_offline_mode, Snackbar.LENGTH_LONG);
> snackbar.show();
> */
> }
> WalletRefreshWorker.enqueue(applicationContext, launched = launch, notifTx = notifTx)
> //
> // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
> // startForegroundService(intent);
> // } else {
> // startService(intent);
> // }
> }
>
> private fun doExplorerView(strHash: String?) {
> if (strHash != null) {
> val blockExplorer = BlockExplorerUtil.getInstance().getUri(true)
> val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(blockExplorer + strHash))
> startActivity(browserIntent)
> }
> }
>
> private fun txDetails(tx: Tx) {
> if (account == WhirlpoolMeta.getInstance(applicationContext).whirlpoolPostmix && tx.amount == 0.0) {
> return
> }
> val txIntent = Intent(this, TxDetailsActivity::class.java)
> txIntent.putExtra("TX", tx.toJSON().toString())
> txIntent.putExtra("_account", account)
> startActivity(txIntent)
> }
>
> private inner class RicochetQueueTask : AsyncTask<String?, Void?, String>() {
>
> override fun onPostExecute(result: String) {
> }
>
> override fun onPreExecute() {
> }
>
> override fun doInBackground(vararg params: String?): String {
> if (RicochetMeta.getInstance(this@BalanceActivity).queue.size > 0) {
> var count = 0
> val itr = RicochetMeta.getInstance(this@BalanceActivity).iterator
> while (itr.hasNext()) {
> if (count == 3) {
> break
> }
> try {
> val jObj = itr.next()
> val jHops = jObj.getJSONArray("hops")
> if (jHops.length() > 0) {
> val jHop = jHops.getJSONObject(jHops.length() - 1)
> val txHash = jHop.getString("hash")
> val txObj = APIFactory.getInstance(this@BalanceActivity).getTxInfo(txHash)
> if (txObj != null && txObj.has("block_height") && txObj.getInt("block_height") != -1) {
> itr.remove()
> count++
> }
> }
> } catch (je: JSONException) {
> }
> }
> }
> if (RicochetMeta.getInstance(this@BalanceActivity).staggered.size > 0) {
> var count = 0
> val staggered = RicochetMeta.getInstance(this@BalanceActivity).staggered
> val _staggered: MutableList<JSONObject> = ArrayList()
> for (jObj in staggered) {
> if (count == 3) {
> break
> }
> try {
> val jHops = jObj.getJSONArray("script")
> if (jHops.length() > 0) {
> val jHop = jHops.getJSONObject(jHops.length() - 1)
> val txHash = jHop.getString("tx")
> val txObj = APIFactory.getInstance(this@BalanceActivity).getTxInfo(txHash)
> if (txObj != null && txObj.has("block_height") && txObj.getInt("block_height") != -1) {
> count++
> } else {
> _staggered.add(jObj)
> }
> }
> } catch (je: JSONException) {
> } catch (cme: ConcurrentModificationException) {
> }
> }
> }
> return "OK"
> }
> }
>
> private fun doFeaturePayNymUpdate() {
> val disposable = Observable.fromCallable {
> var obj = JSONObject()
> obj.put("code", BIP47Util.getInstance(this@BalanceActivity).paymentCode.toString())
> // Log.d("BalanceActivity", obj.toString());
> var res = WebUtil.getInstance(this@BalanceActivity).postURL("application/json", null, WebUtil.PAYNYM_API + "api/v1/token", obj.toString())
> // Log.d("BalanceActivity", res);
> var responseObj = JSONObject(res)
> if (responseObj.has("token")) {
> val token = responseObj.getString("token")
> val sig = MessageSignUtil.getInstance(this@BalanceActivity).signMessage(BIP47Util.getInstance(this@BalanceActivity).notificationAddress.ecKey, token)
> // Log.d("BalanceActivity", sig);
> obj = JSONObject()
> obj.put("nym", BIP47Util.getInstance(this@BalanceActivity).paymentCode.toString())
> obj.put("code", BIP47Util.getInstance(this@BalanceActivity).featurePaymentCode.toString())
> obj.put("signature", sig)
>
> // Log.d("BalanceActivity", "nym/add:" + obj.toString());
> res = WebUtil.getInstance(this@BalanceActivity).postURL("application/json", token, WebUtil.PAYNYM_API + "api/v1/nym/add", obj.toString())
> // Log.d("BalanceActivity", res);
> responseObj = JSONObject(res)
> if (responseObj.has("segwit") && responseObj.has("token")) {
> PrefsUtil.getInstance(this@BalanceActivity).setValue(PrefsUtil.PAYNYM_FEATURED_SEGWIT, true)
> } else if (responseObj.has("claimed") && responseObj.getBoolean("claimed") == true) {
> PrefsUtil.getInstance(this@BalanceActivity).setValue(PrefsUtil.PAYNYM_FEATURED_SEGWIT, true)
> }
> }
> true
> }.subscribeOn(Schedulers.newThread())
> .observeOn(AndroidSchedulers.mainThread())
> .subscribe({ aBoolean: Boolean? -> Log.i(TAG, "doFeaturePayNymUpdate: Feature update complete") }) { error: Throwable? -> Log.i(TAG, "doFeaturePayNymUpdate: Feature update Fail") }
> registerDisposable(disposable)
> }
>
> companion object {
> private const val SCAN_COLD_STORAGE = 2011
> private const val SCAN_QR = 2012
> private const val UTXO_REQUESTCODE = 2012
> private const val TAG = "BalanceActivity"
> const val ACTION_INTENT = "com.samourai.wallet.BalanceFragment.REFRESH"
> const val DISPLAY_INTENT = "com.samourai.wallet.BalanceFragment.DISPLAY"
> }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/home/BalanceViewModel.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/home/BalanceViewModel.java
3a4,8
>
> import androidx.lifecycle.AndroidViewModel;
> import androidx.lifecycle.LiveData;
> import androidx.lifecycle.MutableLiveData;
>
9,11d13
< import androidx.lifecycle.AndroidViewModel;
< import androidx.lifecycle.LiveData;
< import androidx.lifecycle.MutableLiveData;
17d18
< import com.samourai.wallet.util.PrefsUtil;
18a20
> import com.samourai.wallet.util.PrefsUtil;
20a23
> import org.json.JSONException;
22a26
> import java.io.IOException;
58a63,65
> boolean is_sat_prefs = PrefsUtil.getInstance(this.mContext).getValue(PrefsUtil.IS_SAT, true);
> try {
> JSONObject response = new JSONObject("{}");
60c67,68
< final boolean is_sat_prefs = PrefsUtil.getInstance(this.mContext).getValue(PrefsUtil.IS_SAT, true);
---
> if (account == 0) {
> response = PayloadUtil.getInstance(getApplication()).deserializeMultiAddr();
62,114c70,111
< final Disposable disposableJson = Observable.fromCallable(() -> {
< if (account == 0) {
< return PayloadUtil.getInstance(getApplication()).deserializeMultiAddr();
< } else if (account == WhirlpoolMeta.getInstance(getApplication()).getWhirlpoolPostmix()) {
< return PayloadUtil.getInstance(getApplication()).deserializeMultiAddrMix();
< } else {
< return null;
< }
< })
< .subscribeOn(Schedulers.io())
< .observeOn(AndroidSchedulers.mainThread())
< .subscribe(response -> {
< if (response == null) {
< return;
< }
<
< Observable<Pair<List<Tx>, Long>> parser = account == 0
< ? APIFactory.getInstance(getApplication()).parseXPUBObservable(new JSONObject(response.toString()))
< : APIFactory.getInstance(getApplication()).parseMixXPUBObservable(new JSONObject(response.toString()));
< Disposable disposable = parser
< .subscribeOn(Schedulers.computation())
< .observeOn(AndroidSchedulers.mainThread())
< .subscribe(pairValues -> {
< List<Tx> txes = pairValues.first;
< Long xpub_balance = pairValues.second;
< Collections.sort(txes, new APIFactory.TxMostRecentDateComparator());
< txs.postValue(txes);
< toggleSat.setValue(is_sat_prefs);
< if (account == 0) {
< balance.postValue(xpub_balance - BlockedUTXO.getInstance().getTotalValueBlocked0());
< }
< if (account == WhirlpoolMeta.getInstance(getApplication()).getWhirlpoolPostmix()) {
< balance.postValue(xpub_balance - BlockedUTXO.getInstance().getTotalValuePostMix());
< }
< if (account == WhirlpoolMeta.getInstance(getApplication()).getWhirlpoolBadBank()) {
< balance.postValue(xpub_balance - BlockedUTXO.getInstance().getTotalValueBadBank());
< }
< }, error -> {
< LogUtil.info(TAG,error.getMessage());
< txs.postValue(new ArrayList<>());
< toggleSat.setValue(is_sat_prefs);
< balance.postValue(0L);
< });
<
< compositeDisposables.add(disposable);
<
< }, error -> {
< LogUtil.info(TAG,error.getMessage());
< txs.postValue(new ArrayList<>());
< toggleSat.setValue(is_sat_prefs);
< balance.postValue(0L);
< });
< compositeDisposables.add(disposableJson);
---
> }
> if (account == WhirlpoolMeta.getInstance(getApplication()).getWhirlpoolPostmix()) {
> response = PayloadUtil.getInstance(getApplication()).deserializeMultiAddrMix();
> }
>
> if (response != null) {
>
> Observable<Pair<List<Tx>, Long>> parser = account == 0 ? APIFactory.getInstance(getApplication()).parseXPUBObservable(new JSONObject(response.toString())) : APIFactory.getInstance(getApplication()).parseMixXPUBObservable(new JSONObject(response.toString()));
> Disposable disposable = parser
> .subscribeOn(Schedulers.computation())
> .observeOn(AndroidSchedulers.mainThread()).subscribe(pairValues -> {
> List<Tx> txes = pairValues.first;
> Long xpub_balance = pairValues.second;
> Collections.sort(txes, new APIFactory.TxMostRecentDateComparator());
> txs.postValue(txes);
> toggleSat.setValue(is_sat_prefs);
> if (account == 0) {
> balance.postValue(xpub_balance - BlockedUTXO.getInstance().getTotalValueBlocked0());
> }
> if (account == WhirlpoolMeta.getInstance(getApplication()).getWhirlpoolPostmix()) {
> balance.postValue(xpub_balance - BlockedUTXO.getInstance().getTotalValuePostMix());
> }
> if (account == WhirlpoolMeta.getInstance(getApplication()).getWhirlpoolBadBank()) {
> balance.postValue(xpub_balance - BlockedUTXO.getInstance().getTotalValueBadBank());
> }
> }, error -> {
> LogUtil.info(TAG,error.getMessage());
> txs.postValue(new ArrayList<>());
> toggleSat.setValue(is_sat_prefs);
> balance.postValue(0L);
> });
>
> compositeDisposables.add(disposable);
>
> }
>
> } catch (IOException | JSONException e) {
> e.printStackTrace();
> txs.setValue(new ArrayList<>());
> toggleSat.setValue(is_sat_prefs);
> balance.setValue(0L);
> }
152c149
< public void postNewBalance(Long balance) {
---
> public void setBalance(Long balance) {
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/MainActivity2.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/MainActivity2.java
3,10d2
< import static com.samourai.wallet.payload.ExternalBackupManager.backupAvailable;
< import static com.samourai.wallet.payload.ExternalBackupManager.hasBackUpURI;
< import static com.samourai.wallet.util.func.WalletUtil.ASHIGARU_PUB_KEY;
< import static org.apache.commons.lang3.StringUtils.defaultString;
< import static org.apache.commons.lang3.StringUtils.isNotBlank;
< import static org.apache.commons.lang3.StringUtils.strip;
< import static org.apache.commons.lang3.StringUtils.stripStart;
< import static org.apache.commons.lang3.StringUtils.substringBetween;
11a4
> import static java.util.Objects.isNull;
24d16
< import android.util.Log;
29a22
> import androidx.appcompat.app.AppCompatActivity;
31d23
< import androidx.core.content.ContextCompat;
46d37
< import com.samourai.wallet.sync.SyncWalletActivity;
53,54d43
< import com.samourai.wallet.util.Util;
< import com.samourai.wallet.util.func.WalletUtil;
56d44
< import com.samourai.wallet.util.network.WebUtil;
62d49
< import com.samourai.wallet.util.tech.VerifyPGPSignedClearMessageUtil;
66d52
< import org.apache.commons.lang3.StringUtils;
70d55
< import org.json.JSONObject;
74,76d58
< import java.util.concurrent.ExecutorService;
< import java.util.concurrent.Executors;
< import java.util.concurrent.atomic.AtomicBoolean;
79d60
< import io.reactivex.Observable;
85c66
< public class MainActivity2 extends SamouraiActivity {
---
> public class MainActivity2 extends AppCompatActivity {
89a71
> private boolean pinEntryActivityLaunched = false;
97d78
< private AtomicBoolean torStateObserverInitialized = new AtomicBoolean(false);
151,165d131
<
< // if (BuildConfig.DEBUG) { // useful to detect bad usage of main thread for developers
< // StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
< // .detectCustomSlowCalls()
< // .detectNetwork()
< // .detectDiskReads()
< // .penaltyLog()
< // .build());
< // StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
< // .detectLeakedSqlLiteObjects()
< // .detectLeakedClosableObjects()
< // .penaltyLog()
< // .build());
< // }
<
168,169d133
< getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.window));
<
177,178d140
< BalanceActivity.Companion.setAppUpdateShowed(false);
< SamouraiWallet.getInstance().releaseNotes = null;
180,192c142,151
< final Disposable disposable = Observable.fromCallable(() -> {
< return PrefsUtil.getInstance(MainActivity2.this).getValue(PrefsUtil.TESTNET, false);
< })
< .subscribeOn(Schedulers.io())
< .observeOn(AndroidSchedulers.mainThread())
< .subscribe(isTestNet -> {
< if (isTestNet) {
< SamouraiWallet.getInstance().setCurrentNetworkParams(TestNet3Params.get());
< }
< BackgroundManager.get(MainActivity2.this).addListener(bgListener);
< startApp();
< });
< compositeDisposables.add(disposable);
---
>
> if (PrefsUtil.getInstance(MainActivity2.this).getValue(PrefsUtil.TESTNET, false) == true) {
> SamouraiWallet.getInstance().setCurrentNetworkParams(TestNet3Params.get());
> }
>
> // if(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
> BackgroundManager.get(MainActivity2.this).addListener(bgListener);
> // }
>
> startApp();
195c154,155
< private void startApp() {
---
> @Override
> protected void onResume() {
197,199c157,158
< if (SamouraiTorManager.INSTANCE.isRequired() &&
< !AppUtil.getInstance(getApplicationContext()).isOfflineMode() &&
< ConnectivityStatus.hasConnectivity(getApplicationContext()) &&
---
> if (PrefsUtil.getInstance(this).getValue(PrefsUtil.ENABLE_TOR, false) &&
> !PrefsUtil.getInstance(this).getValue(PrefsUtil.OFFLINE,false) &&
201a161
> progressIndicator.setIndeterminate(true);
203c163
< loaderTxView.setText(getText(R.string.initializing_tor));
---
> SamouraiTorManager.INSTANCE.start();
206c166
< initAppOnCreate();
---
> initAppOnResume();
207a168,169
> super.onResume();
>
210,211c172
< @Override
< protected void onResume() {
---
> private void startApp() {
218d178
< progressIndicator.setIndeterminate(true);
220c180
< SamouraiTorManager.INSTANCE.start();
---
> loaderTxView.setText(getText(R.string.initializing_tor));
223c183
< initAppOnResume();
---
> initAppOnCreate();
225,226d184
< super.onResume();
<
233c191
< doAppInit0(false, null);
---
> doAppInit0(false, null, null);
242a201
> String strPCode = null;
252a212,214
> if (extras != null && extras.containsKey("pcode")) {
> strPCode = extras.getString("pcode");
> }
258c220,221
< doAppInit0(isDial, strUri);
---
> doAppInit0(isDial, strUri, strPCode);
>
264,268c227,243
< if (torStateObserverInitialized.compareAndSet(false, true)) {
< if (torStateObserver == null) {
< torStateObserver = new Observer<TorState>() {
< @Override
< public void onChanged(TorState torState) {
---
> if (isNull(torStateObserver)) {
> torStateObserver = new Observer<TorState>() {
> @Override
> public void onChanged(TorState torState) {
>
> SimpleTaskRunner.create().executeAsync(new Callable<Integer>() {
> @Override
> public Integer call() throws Exception {
> final int progressIndicatorValue = torState.getProgressIndicator();
> final int newProgressIndicatorValue = max(
> progressIndicatorValue,
> progressIndicator.getProgress());
> return newProgressIndicatorValue;
> }
> }, new SimpleCallback<Integer>() {
> @Override
> public void onComplete(final Integer newProgressIndicatorValue) {
270,283c245,247
< SimpleTaskRunner.create().executeAsync(
< true,
< new Callable<Integer>() {
< @Override
< public Integer call() throws Exception {
< final int progressIndicatorValue = torState.getProgressIndicator();
< final int newProgressIndicatorValue = max(
< progressIndicatorValue,
< progressIndicator.getProgress());
< return newProgressIndicatorValue;
< }
< }, new SimpleCallback<Integer>() {
< @Override
< public void onComplete(final Integer newProgressIndicatorValue) {
---
> if (newProgressIndicatorValue > 0 && progressIndicator.isIndeterminate()) {
> progressIndicator.setIndeterminate(false);
> }
285,286c249,254
< if (newProgressIndicatorValue > 0 && progressIndicator.isIndeterminate()) {
< progressIndicator.setIndeterminate(false);
---
> SimpleTaskRunner.create().executeAsync(new Callable<Boolean>() {
> @Override
> public Boolean call() throws Exception {
> if (progressIndicator.getProgress() <= 0 && newProgressIndicatorValue > 0) {
> ThreadHelper.pauseMillis(100L);
> return true;
288,302c256,270
<
< SimpleTaskRunner.create().executeAsync(true, new Callable<Boolean>() {
< @Override
< public Boolean call() throws Exception {
< if (progressIndicator.getProgress() <= 0 && newProgressIndicatorValue > 0) {
< ThreadHelper.pauseMillis(100L);
< return true;
< }
< return false;
< }
< }, new SimpleCallback<Boolean>() {
< @Override
< public void onComplete(final Boolean stateChanged) {
< if (newProgressIndicatorValue > 0) {
< progressIndicator.setProgressCompat(newProgressIndicatorValue, true);
---
> return false;
> }
> }, new SimpleCallback<Boolean>() {
> @Override
> public void onComplete(final Boolean stateChanged) {
> if (newProgressIndicatorValue > 0) {
> progressIndicator.setProgressCompat(newProgressIndicatorValue, true);
> }
> if (torState.getState() == EnumTorState.ON) {
> SimpleTaskRunner.create().executeAsync(new Callable<Object>() {
> @Override
> public Object call() throws Exception {
> // wait for progress bar to reach 100%
> ThreadUtils.sleep(Duration.ofMillis(500));
> return null;
304,317c272,275
< if (torState.getState() == EnumTorState.ON) {
< SimpleTaskRunner.create().executeAsync(true, new Callable<Object>() {
< @Override
< public Object call() throws Exception {
< // wait for progress bar to reach 100%
< ThreadUtils.sleep(Duration.ofMillis(500));
< return null;
< }
< }, new SimpleCallback<Object>() {
< @Override
< public void onComplete(Object result) {
< SimpleTaskRunner.create().executeAsyncAndShutdown(() -> initAppOnCreate());
< }
< });
---
> }, new SimpleCallback<Object>() {
> @Override
> public void onComplete(Object result) {
> SimpleTaskRunner.create().executeAsync(() -> initAppOnCreate());
319,326c277,285
< }
< });
< }
< });
< }
< };
< SamouraiTorManager.INSTANCE.getTorStateLiveData().observe(this, torStateObserver);
< }
---
> });
> }
> }
> });
> }
> });
> }
> };
> SamouraiTorManager.INSTANCE.getTorStateLiveData().observe(this, torStateObserver);
334,356c293,294
< SimpleTaskRunner.create().executeAsync(
< true,
< new Callable<Void>() {
< @Override
< public Void call() throws Exception {
< AppUtil.getInstance(MainActivity2.this).deleteQR();
< AppUtil.getInstance(MainActivity2.this).deleteBackup();
< return null;
< }
< },
< new SimpleCallback<Void>() {
< @Override
< public void onComplete(Void result) {
< IntentFilter filter_restart = new IntentFilter(ACTION_RESTART);
< LocalBroadcastManager.getInstance(MainActivity2.this).registerReceiver(receiver_restart, filter_restart);
< String strUri = null;
< try {
< String action = getIntent().getAction();
< String scheme = getIntent().getScheme();
< if (action != null && Intent.ACTION_VIEW.equals(action) && scheme.equals("bitcoin")) {
< strUri = getIntent().getData().toString();
< } else {
< Bundle extras = getIntent().getExtras();
---
> AppUtil.getInstance(MainActivity2.this).deleteQR();
> AppUtil.getInstance(MainActivity2.this).deleteBackup();
358,361c296,305
< if (extras != null && extras.containsKey("uri")) {
< strUri = extras.getString("uri");
< }
< }
---
> IntentFilter filter_restart = new IntentFilter(ACTION_RESTART);
> LocalBroadcastManager.getInstance(MainActivity2.this).registerReceiver(receiver_restart, filter_restart);
> String strUri = null;
> try {
> String action = getIntent().getAction();
> String scheme = getIntent().getScheme();
> if (action != null && Intent.ACTION_VIEW.equals(action) && scheme.equals("bitcoin")) {
> strUri = getIntent().getData().toString();
> } else {
> Bundle extras = getIntent().getExtras();
363,370c307,318
< if ( scheme !=null && scheme.equals("auth47") && getIntent().getData()!=null) {
< strUri = getIntent().getData().toString();
< }
< } catch (Exception e) {
< e.printStackTrace();
< }
< doAppInit0(false, strUri);
< }
---
> if (extras != null && extras.containsKey("uri")) {
> strUri = extras.getString("uri");
> }
> }
>
> if ( scheme !=null && scheme.equals("auth47") && getIntent().getData()!=null) {
> strUri = getIntent().getData().toString();
> }
> } catch (Exception e) {
> e.printStackTrace();
> }
> doAppInit0(false, strUri, null);
372,376d319
< @Override
< public void onException(Throwable t) {
< Log.e(TAG, "issue on initAppOnResume()", t);
< }
< });
390a334,335
> AppUtil.getInstance(MainActivity2.this).deleteQR();
> AppUtil.getInstance(MainActivity2.this).deleteBackup();
392,410c337
< SimpleTaskRunner.create().executeAsync(
< true,
< () -> {
< AppUtil.getInstance(MainActivity2.this).deleteQR();
< AppUtil.getInstance(MainActivity2.this).deleteBackup();
< return null;
< },
< new SimpleCallback<Void>() {
< @Override
< public void onComplete(Void result) {
< SimpleCallback.super.onComplete(result);
< }
<
< @Override
< public void onException(Throwable t) {
< Log.e(TAG, "issue on delete resources", t);
< }
< });
<
---
> // if(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
411a339
> // }
423,425c351,368
< if (AccessFactory.getInstance(MainActivity2.this).isLoggedIn() && !TimeOutUtil.getInstance().isTimedOut()) {
< return;
< }
---
> if (!pinEntryActivityLaunched) {
>
> if (AccessFactory.getInstance(MainActivity2.this).isLoggedIn() && !TimeOutUtil.getInstance().isTimedOut()) {
> return;
> }
>
> AccessFactory.getInstance(MainActivity2.this).setIsLoggedIn(false);
> final Intent intent = new Intent(MainActivity2.this, PinEntryActivity.class);
> if (strUri != null) {
> intent.putExtra("uri", strUri);
> PrefsUtil.getInstance(MainActivity2.this).setValue("SCHEMED_URI", strUri);
> }
> if (getBundleExtras() != null) {
> intent.putExtras(getBundleExtras());
> }
> startActivity(intent);
> finish();
> pinEntryActivityLaunched = true;
427,434d369
< AccessFactory.getInstance(MainActivity2.this).setIsLoggedIn(false);
< final Intent intent = new Intent(MainActivity2.this, PinEntryActivity.class);
< if (strUri != null) {
< intent.putExtra("uri", strUri);
< PrefsUtil.getInstance(MainActivity2.this).setValue("SCHEMED_URI", strUri);
< }
< if (getBundleExtras() != null) {
< intent.putExtras(getBundleExtras());
436,437d370
< startActivity(intent);
< finish();
478a412
>
486c420
< private void doAppInit0(final boolean isDial, final String strUri) {
---
> private void doAppInit0(final boolean isDial, final String strUri, final String strPCode) {
491c425
< doAppInit1(isDial, strUri);
---
> doAppInit1(isDial, strUri, strPCode);
494d427
<
509c442
< doAppInit1(isDial, strUri);
---
> doAppInit1(isDial, strUri, strPCode);
514c447
< doAppInit1(isDial, strUri);
---
> doAppInit1(isDial, strUri, strPCode);
556c489
< synchronized private void doAppInit1(boolean isDial, final String strUri) {
---
> private void doAppInit1(boolean isDial, final String strUri, final String strPCode) {
572d504
<
575,578c507,511
< boolean walletScanComplete = isWalletScanComplete();
<
< if (!walletScanComplete && hasBackUpURI() && !backupAvailable()) {
< WalletUtil.saveWallet(this);
---
> Intent intent = new Intent(MainActivity2.this, BalanceActivity.class);
> intent.putExtra("notifTx", true);
> intent.putExtra("fetch", true);
> if(strUri != null){
> intent.putExtra("uri", strUri);
580,587c513,514
<
< if(!walletScanComplete && !AppUtil.getInstance(this).isOfflineMode()) {
< startSyncWalletActivity(strUri);
< } else {
< if (!AppUtil.getInstance(this).isOfflineMode()) {
< checkForAppUpdates();
< }
< startBalanceActivity(strUri);
---
> if (getBundleExtras() != null) {
> intent.putExtras(getBundleExtras());
589c516
<
---
> startActivity(intent);
594,611d520
< }
<
< private boolean isWalletScanComplete() {
< return PrefsUtil.getInstance(this).getValue(PrefsUtil.WALLET_SCAN_COMPLETE, false);
< }
<
< private void startSyncWalletActivity(final String strUri) {
< final Intent intent = new Intent(MainActivity2.this, SyncWalletActivity.class);
< intent.putExtra("notifTx", true);
< intent.putExtra("fetch", true);
< if(strUri != null) {
< intent.putExtra("uri", strUri);
< }
< if (getBundleExtras() != null) {
< intent.putExtras(getBundleExtras());
< }
< startActivity(intent);
< }
613,623d521
< private void startBalanceActivity(final String strUri) {
< final Intent intent = new Intent(MainActivity2.this, BalanceActivity.class);
< intent.putExtra("notifTx", true);
< intent.putExtra("fetch", true);
< if(strUri != null){
< intent.putExtra("uri", strUri);
< }
< if (getBundleExtras() != null) {
< intent.putExtras(getBundleExtras());
< }
< startActivity(intent);
671c569
< .setTitle("Ashigaru")
---
> .setTitle("Samourai")
684,732d581
< }
<
< private void checkForAppUpdates() {
< ExecutorService executor = Executors.newSingleThreadExecutor();
< executor.execute(() -> {
< try {
< String latestVersionMessage = WebUtil.getInstance(null).getURL("http://lbpxfhbnfyhxmy3jl6a4q7dzpeobx7cvkghz2vvwygevq3k4ilo2v5ad.onion/Ashigaru/Ashigaru-Mobile/raw/branch/main/accompanying-release-files/ashigaru_mobile_latest.txt");
< // 1. If the message is signed with Ashigaru's Dev public key
< // If it's correct, proceed; otherwise, return and don't check anything else
< if (!VerifyPGPSignedClearMessageUtil.verifySignedMessage(
< defaultString(latestVersionMessage),
< ASHIGARU_PUB_KEY))
< return;
< final String releaseNotes = WebUtil.getInstance(null).getURL("http://lbpxfhbnfyhxmy3jl6a4q7dzpeobx7cvkghz2vvwygevq3k4ilo2v5ad.onion/Ashigaru/Ashigaru-Mobile/raw/branch/main/accompanying-release-files/ashigaru_mobile_release_notes.txt");
<
< final String releaseNotesSha256 = Util.sha256Hex(defaultString(releaseNotes));
< final String releaseNoteSha256ToVerify = substringBetween(latestVersionMessage, "ashigaru_mobile_release_notes.txt_sha256hash=", "\n");
< if (! StringUtils.equals(releaseNotesSha256, releaseNoteSha256ToVerify)) {
< return;
< }
<
< JSONObject releaseNotesJSON = null;
< if (isNotBlank(releaseNotes)) {
< try {
< releaseNotesJSON = new JSONObject(releaseNotes);
< } catch (final Exception e) {
< Log.e(TAG, e.getMessage(), e);
< releaseNotesJSON = null;
< }
< }
< if (releaseNotesJSON == null) {
< Log.w(TAG, "releaseNotesJSON is null");
< return;
< }
< SamouraiWallet.getInstance().releaseNotes = releaseNotesJSON;
<
< final String latestVersion = strip(stripStart(substringBetween(latestVersionMessage, "latest_ashigaru_mobile_version=", "\n"), "v"));
< boolean noNeedToShow = latestVersion.equals(stripStart(BuildConfig.VERSION_NAME, "v"));
< runOnUiThread(() -> {
< AppUtil.getInstance(this).setHasUpdateBeenShown(noNeedToShow);
< });
<
< } catch (Exception e) {
< e.printStackTrace();
< runOnUiThread(() -> {
< System.out.println("Failed to fetch app updated");
< });
< }
< });
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/network/dojo/DojoUtil.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/network/dojo/DojoUtil.java
8d7
< import com.samourai.wallet.util.PrefsUtil;
23d21
< private static String dojoName = "My Dojo";
71,73d68
< public String getDojoName() {
< return dojoName;
< }
76,101c71,95
< return Observable.fromCallable(() -> {
<
< DojoUtil.dojoParams = dojoParams;
< Log.i(TAG, "setDojoParams: ".concat(dojoParams));
< String url = getUrl(dojoParams);
<
< if(url.charAt(url.length() - 1) != '/') {
< url = url + "/";
<
< JSONObject obj = new JSONObject(dojoParams);
< if(obj.has("pairing") && obj.getJSONObject("pairing").has("url")) {
< obj.getJSONObject("pairing").put("url", url);
< DojoUtil.dojoParams = obj.toString();
< }
< }
<
< if(SamouraiWallet.getInstance().isTestNet()) {
< WebUtil.SAMOURAI_API2_TESTNET_TOR = url;
< } else {
< WebUtil.SAMOURAI_API2_TOR = url;
< }
<
< String apiToken = getApiKey(dojoParams);
< APIFactory.getInstance(context).setAppToken(apiToken);
< return APIFactory.getInstance(context).getToken(true, false);
< });
---
> return Observable.fromCallable(() -> {
> DojoUtil.dojoParams = dojoParams;
> Log.i(TAG, "setDojoParams: ".concat(dojoParams));
> String url = getUrl(dojoParams);
> if(url.charAt(url.length() - 1) != '/') {
> url = url + "/";
>
> JSONObject obj = new JSONObject(dojoParams);
> if(obj.has("pairing") && obj.getJSONObject("pairing").has("url")) {
> obj.getJSONObject("pairing").put("url", url);
> DojoUtil.dojoParams = obj.toString();
> }
> }
> if(SamouraiWallet.getInstance().isTestNet()) {
> WebUtil.SAMOURAI_API2_TESTNET_TOR = url;
> }
> else {
> WebUtil.SAMOURAI_API2_TOR = url;
> }
>
> String apiToken = getApiKey(dojoParams);
> APIFactory.getInstance(context).setAppToken(apiToken);
> boolean tokenRetrieved = APIFactory.getInstance(context).getToken(true, false);
> return tokenRetrieved;
> });
117,141d110
< public synchronized void setDojoParamsOfflineMode(String dojoParams) throws JSONException {
< DojoUtil.dojoParams = dojoParams;
< Log.i(TAG, "setDojoParams: ".concat(dojoParams));
< String url = getUrl(dojoParams);
<
< if(url.charAt(url.length() - 1) != '/') {
< url = url + "/";
<
< JSONObject obj = new JSONObject(dojoParams);
< if(obj.has("pairing") && obj.getJSONObject("pairing").has("url")) {
< obj.getJSONObject("pairing").put("url", url);
< DojoUtil.dojoParams = obj.toString();
< }
< }
<
< if(SamouraiWallet.getInstance().isTestNet()) {
< WebUtil.SAMOURAI_API2_TESTNET_TOR = url;
< } else {
< WebUtil.SAMOURAI_API2_TOR = url;
< }
<
< String apiToken = getApiKey(dojoParams);
< APIFactory.getInstance(context).setAppToken(apiToken);
< }
<
157c126,140
< return isGreaterOrEqualThanVersionOneDot(11);
---
> String[] s = dojoVersion.split("\\.");
> try {
> if(s.length >= 1 && Integer.parseInt(s[0]) > 1) {
> return true;
> }
> else if(s.length >= 2 && Integer.parseInt(s[0]) == 1 && Integer.parseInt(s[1]) >= 11){
> return true;
> }
> else {
> return false;
> }
> }
> catch(NumberFormatException nfe) {
> return false;
> }
168c151,165
< return isGreaterOrEqualThanVersionOneDot(13);
---
> String[] s = dojoVersion.split("\\.");
> try {
> if(s.length >= 1 && Integer.parseInt(s[0]) > 1) {
> return true;
> }
> else if(s.length >= 2 && Integer.parseInt(s[0]) == 1 && Integer.parseInt(s[1]) >= 13){
> return true;
> }
> else {
> return false;
> }
> }
> catch(NumberFormatException nfe) {
> return false;
> }
226a224
>
228c226,241
< return isGreaterOrEqualThanVersionOneDot(23);
---
> String[] s = dojoVersion.split("\\.");
> try {
> if(s.length >= 1 && Integer.parseInt(s[0]) > 1) {
> return true;
> }
> else if(s.length >= 2 && Integer.parseInt(s[0]) == 1 && Integer.parseInt(s[1]) >= 23){
> return true;
> }
> else {
> return false;
> }
> }
> catch(NumberFormatException nfe) {
> return false;
> }
>
238,247c251
< return isGreaterOrEqualThanVersionOneDot(22);
<
< }
<
< public String getVersion(String data) {
<
< if(!isValidPairingPayload(data)) {
< return null;
< }
<
---
> String[] s = dojoVersion.split("\\.");
249,251c253,261
< JSONObject obj = new JSONObject(data);
< JSONObject pObj = obj.getJSONObject("pairing");
< return pObj.getString("version");
---
> if(s.length >= 1 && Integer.parseInt(s[0]) > 1) {
> return true;
> }
> else if(s.length >= 2 && Integer.parseInt(s[0]) == 1 && Integer.parseInt(s[1]) >= 22){
> return true;
> }
> else {
> return false;
> }
253,254c263,264
< catch(JSONException je) {
< return null;
---
> catch(NumberFormatException nfe) {
> return false;
259c269
< public String getExplorerUrl(String data) {
---
> public String getVersion(String data) {
267,268c277,278
< JSONObject pObj = obj.getJSONObject("explorer");
< return pObj.getString("url");
---
> JSONObject pObj = obj.getJSONObject("pairing");
> return pObj.getString("version");
317,323d326
< String blockExplorer = PrefsUtil.getInstance(context).getValue(PrefsUtil.BLOCK_EXPLORER_URL, "");
< if (blockExplorer != null && !blockExplorer.isEmpty()) {
< JSONObject explorerJSON = new JSONObject();
< explorerJSON.put("type", "explorer.btc_rpc_explorer");
< explorerJSON.put("url", blockExplorer);
< obj.put("explorer", explorerJSON);
< }
342,346c345
< if (SamouraiWallet.getInstance().isTestNet()) {
< WebUtil.SAMOURAI_API2_TESTNET_TOR = getUrl(dojoParams);
< } else {
< WebUtil.SAMOURAI_API2_TOR = getUrl(dojoParams);
< }
---
> if (dojoParams != null) {
348,349c347,351
< String apiToken = getApiKey(dojoParams);
< APIFactory.getInstance(context).setAppToken(apiToken);
---
> if (SamouraiWallet.getInstance().isTestNet()) {
> WebUtil.SAMOURAI_API2_TESTNET_TOR = getUrl(dojoParams);
> } else {
> WebUtil.SAMOURAI_API2_TOR = getUrl(dojoParams);
> }
351,352c353,354
< }
< }
---
> String apiToken = getApiKey(dojoParams);
> APIFactory.getInstance(context).setAppToken(apiToken);
354,362d355
< private static boolean isGreaterOrEqualThanVersionOneDot(final int middle) {
< String[] s = dojoVersion.split("\\.");
< try {
< if (s.length >= 1 && Integer.parseInt(s[0]) > 1) {
< return true;
< } else if (s.length >= 2 && Integer.parseInt(s[0]) == 1 && Integer.parseInt(s[1]) >= middle) {
< return true;
< } else {
< return false;
364,365c357
< } catch (NumberFormatException nfe) {
< return false;
---
>
366a359
>
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/network/NetworkDashboard.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/network/NetworkDashboard.java
29d28
< import com.samourai.wallet.network.dojo.DojoDetailsActivity;
31a31
> import com.samourai.wallet.service.WebSocketService;
39d38
< import com.samourai.wallet.util.tech.LogUtil;
42d40
<
45d42
< import io.reactivex.android.schedulers.AndroidSchedulers;
47,48d43
< import io.reactivex.disposables.Disposable;
< import io.reactivex.schedulers.Schedulers;
56c51
< //Button torButton;
---
> Button torButton;
58,59c53,57
< TextView dojoName;
< ImageView dojoDetailsButton;
---
> Button dojoBtn;
> TextView dataConnectionStatus;
> TextView torRenewBtn;
> TextView torConnectionStatus;
> TextView dojoConnectionStatus;
79,80d76
< getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.window));
< getWindow().setNavigationBarColor(ContextCompat.getColor(this, R.color.networking));
90,93c86,92
< dojoName = findViewById(R.id.dojoName);
< dojoDetailsButton = findViewById(R.id.dojoRightBtn);
< //torButton = findViewById(R.id.networking_tor_btn);
<
---
> torButton = findViewById(R.id.networking_tor_btn);
> dojoBtn = findViewById(R.id.networking_dojo_btn);
> torRenewBtn = findViewById(R.id.networking_tor_renew);
>
> dataConnectionStatus = findViewById(R.id.network_data_status);
> torConnectionStatus = findViewById(R.id.network_tor_status);
> dojoConnectionStatus = findViewById(R.id.network_dojo_status);
107,113c106,109
< if (!PrefsUtil.getInstance(getApplicationContext()).getValue(PrefsUtil.DOJO_NAME, "").isEmpty())
< dojoName.setText(PrefsUtil.getInstance(getApplicationContext()).getValue(PrefsUtil.DOJO_NAME, ""));
<
< dojoLayout = findViewById(R.id.network_dojo_layout);
<
< dojoLayout.setOnClickListener(v -> {
< startActivity(new Intent(this, DojoDetailsActivity.class));
---
> torRenewBtn.setOnClickListener(view -> {
> if (SamouraiTorManager.INSTANCE.isConnected()) {
> SamouraiTorManager.newIdentity();
> }
115,116d110
<
< /*
136,137c130
< */
< /*
---
>
163c156
< */
---
>
168a162
> dojoLayout = findViewById(R.id.network_dojo_layout);
174c168
< resetApiConfig();
---
> resetAPI();
189,195d182
< @Override
< protected void onResume() {
< super.onResume();
< if (!PrefsUtil.getInstance(getApplicationContext()).getValue(PrefsUtil.DOJO_NAME, "").isEmpty())
< dojoName.setText(PrefsUtil.getInstance(getApplicationContext()).getValue(PrefsUtil.DOJO_NAME, ""));
< }
<
197c184
< SimpleTaskRunner.create().executeAsyncAndShutdown(() -> {
---
> SimpleTaskRunner.create().executeAsync(() -> {
257c244
< //if (SamouraiTorManager.INSTANCE.isRequired() && !SamouraiTorManager.INSTANCE.isConnected()) {
---
> if (SamouraiTorManager.INSTANCE.isRequired() && !SamouraiTorManager.INSTANCE.isConnected()) {
259c246
< //}
---
> }
266c253
< Snackbar.make(dojoDetailsButton.getRootView(), "No data connection", Snackbar.LENGTH_SHORT).show();
---
> Snackbar.make(torButton.getRootView(), "No data connection", Snackbar.LENGTH_SHORT).show();
289a277
> dataConnectionStatus.setText("Enabled");
293a282
> dataConnectionStatus.setText("Disabled");
303c292
< //dojoBtn.setText("Disable");
---
> dojoBtn.setText("Disable");
304a294
> dojoConnectionStatus.setText("Enabled");
306c296
< //dojoBtn.setText("configure");
---
> dojoBtn.setText("configure");
307a298
> dojoConnectionStatus.setText("Not configured");
309c300
< //dojoBtn.setText("Enable");
---
> dojoBtn.setText("Enable");
310a302
> dojoConnectionStatus.setText("Disabled");
319,320c311,312
< //torButton.setText("Disable");
< //torButton.setEnabled(true);
---
> torButton.setText("Disable");
> torButton.setEnabled(true);
321a314,315
> torConnectionStatus.setText("Enabled");
> torRenewBtn.setVisibility(View.VISIBLE);
324c318,324
< initDojoWithPairingParams();
---
>
> if (strPairingParams != null) {
> DojoUtil.getInstance(NetworkDashboard.this).setDojoParams(strPairingParams);
> Toast.makeText(NetworkDashboard.this, "Tor enabled for Dojo pairing:" + DojoUtil.getInstance(NetworkDashboard.this).getDojoParams(), Toast.LENGTH_SHORT).show();
> initDojo();
> }
>
328,329c328,330
< // torButton.setText("loading...");
< // torButton.setEnabled(false);
---
> torRenewBtn.setVisibility(View.INVISIBLE);
> torButton.setText("loading...");
> torButton.setEnabled(false);
330a332
> torConnectionStatus.setText("Tor initializing");
332,333c334,336
< // torButton.setText("Enable");
< // torButton.setEnabled(true);
---
> torRenewBtn.setVisibility(View.INVISIBLE);
> torButton.setText("Enable");
> torButton.setEnabled(true);
334a338
> torConnectionStatus.setText("Disabled");
347c351
< Snackbar.make(dojoDetailsButton.getRootView(), R.string.in_offline_mode, Snackbar.LENGTH_LONG)
---
> Snackbar.make(torButton.getRootView(), R.string.in_offline_mode, Snackbar.LENGTH_LONG)
369,397c373,375
<
<
< if (! SamouraiTorManager.INSTANCE.isConnected() &&
< ! SamouraiTorManager.INSTANCE.isStarting()) {
<
< waitingForPairing = true;
< startTor();
< PrefsUtil.getInstance(getApplicationContext()).setValue(PrefsUtil.ENABLE_TOR, true);
< } else {
< waitingForPairing = false;
< initDojoWithPairingParams();
< }
< }
<
< private void initDojoWithPairingParams() {
< if (strPairingParams != null) {
< final Disposable disposable = DojoUtil.getInstance(NetworkDashboard.this)
< .setDojoParams(strPairingParams)
< .subscribeOn(Schedulers.io())
< .observeOn(AndroidSchedulers.mainThread()).subscribe((aBoolean) -> {
< initDojo();
< Toast.makeText(
< NetworkDashboard.this,
< "Tor enabled for Dojo pairing:"
< + DojoUtil.getInstance(NetworkDashboard.this).getDojoParams(),
< Toast.LENGTH_SHORT).show();
< }, throwable -> LogUtil.error(TAG, throwable));
< disposables.add(disposable);
< }
---
> waitingForPairing = true;
> startTor();
> PrefsUtil.getInstance(getApplicationContext()).setValue(PrefsUtil.ENABLE_TOR, true);
420,422c398,400
< if (Objects.nonNull(WebUtil.SAMOURAI_API2_TESTNET_TOR)) {
< Log.d("NetworkDashboard", WebUtil.SAMOURAI_API2_TESTNET_TOR);
< }
---
> Log.d("NetworkDashboard", WebUtil.SAMOURAI_API2_TESTNET_TOR);
>
> resetAPI();
445,468c423,458
< private void resetApiConfig() {
< // PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUB44REG, false);
< PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUB49REG, false);
< PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUB84REG, false);
< PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBPREREG, false);
< PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBPOSTREG, false);
< PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBBADBANKREG, false);
< PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBRICOCHETREG, false);
< PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUB44LOCK, false);
< PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUB49LOCK, false);
< PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUB84LOCK, false);
< PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBPRELOCK, false);
< PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBPOSTLOCK, false);
< PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBBADBANKLOCK, false);
< PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBRICOCHETLOCK, false);
<
< DojoUtil.getInstance(NetworkDashboard.this).clear();
< APIFactory.getInstance(NetworkDashboard.this).setAccessToken(null);
< APIFactory.getInstance(NetworkDashboard.this).setAppToken(null);
< try {
< APIFactory.getInstance(NetworkDashboard.this).getToken(true, false);
< } catch (Exception e) {
< e.printStackTrace();
< }
---
> private void resetAPI() {
>
> new Thread(new Runnable() {
> @Override
> public void run() {
> Looper.prepare();
>
> // PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUB44REG, false);
> PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUB49REG, false);
> PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUB84REG, false);
> PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBPREREG, false);
> PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBPOSTREG, false);
> PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBBADBANKREG, false);
> PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBRICOCHETREG, false);
> PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUB44LOCK, false);
> PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUB49LOCK, false);
> PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUB84LOCK, false);
> PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBPRELOCK, false);
> PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBPOSTLOCK, false);
> PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBBADBANKLOCK, false);
> PrefsUtil.getInstance(NetworkDashboard.this).setValue(PrefsUtil.XPUBRICOCHETLOCK, false);
>
> DojoUtil.getInstance(NetworkDashboard.this).clear();
> APIFactory.getInstance(NetworkDashboard.this).setAccessToken(null);
> APIFactory.getInstance(NetworkDashboard.this).setAppToken(null);
> try {
> APIFactory.getInstance(NetworkDashboard.this).getToken(true, false);
> } catch (Exception e) {
> e.printStackTrace();
> }
>
> Looper.loop();
>
> }
> }).start();
>
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard/OnBoardSlidesActivity.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/onboard/OnBoardSlidesActivity.kt
28d27
< window.navigationBarColor = ContextCompat.getColor(this, R.color.window);
31c30
< startActivity(Intent(this, CreateOrRestoreActivity::class.java))
---
> startActivity(Intent(this, SetUpWalletActivity::class.java))
35c34
< override fun getItemCount(): Int = 3
---
> override fun getItemCount(): Int = 4
44a44
> R.drawable.ic_offline_slider,
49a50
> R.string.offline_mode_allows,
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard/RestoreOptionActivity.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/onboard/RestoreOptionActivity.kt
213a214,218
>
> override fun onCreateOptionsMenu(menu: Menu): Boolean {
> menuInflater.inflate(R.menu.landing_activity_menu, menu)
> return true
> }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard/SetUpWalletActivity.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/onboard/SetUpWalletActivity.kt
3,4d2
< import android.content.ClipboardManager
< import android.content.Context
12d9
< import android.widget.Toast
34d30
< import com.samourai.wallet.util.tech.AppUtil
154,178c150
< val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
< val string = if (clipboard.hasPrimaryClip()) {
< val item = clipboard.primaryClip?.getItemAt(0)
< item?.text.toString()
< } else {
< ""
< }
< if (DojoUtil.getInstance(applicationContext).isValidPairingPayload(string)) {
< binding.jsonDojoTextField.text = string
< try {
< setUpWalletViewModel.viewModelScope.launch(Dispatchers.Default) {
< withContext(Dispatchers.Main) {
< setUpWalletViewModel.setDojoParams(string, applicationContext)
< }
< delay(600)
< withContext(Dispatchers.Main) {
< connectDojo()
< }
< }
< } catch (e: Exception) {
< }
< }
< else
< Toast.makeText(applicationContext, "Clipboard doesn't contain a valid Dojo pairing payload", Toast.LENGTH_LONG).show()
<
---
> connectDojo()
181,191c153,154
< if (DojoUtil.getInstance(this@SetUpWalletActivity).dojoParams != null || AppUtil.getInstance(this@SetUpWalletActivity).isOfflineMode) {
< val intent = Intent(this, CreateWalletActivity::class.java)
< startActivity(intent)
< }
< else {
< Toast.makeText(
< this@SetUpWalletActivity,
< "No Dojo credentials. Enter these to create a wallet. Or go offline.",
< Toast.LENGTH_LONG
< ).show()
< }
---
> val intent = Intent(this, CreateWalletActivity::class.java)
> startActivity(intent)
194,204c157,158
< if (DojoUtil.getInstance(this@SetUpWalletActivity).dojoParams != null || AppUtil.getInstance(this@SetUpWalletActivity).isOfflineMode) {
< val intent = Intent(this, RestoreOptionActivity::class.java)
< startActivity(intent)
< }
< else {
< Toast.makeText(
< this@SetUpWalletActivity,
< "No Dojo credentials. Enter these to restore a wallet. Or go offline.",
< Toast.LENGTH_LONG
< ).show()
< }
---
> val intent = Intent(this, RestoreOptionActivity::class.java)
> startActivity(intent)
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/onboard/SetUpWalletViewModel.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/onboard/SetUpWalletViewModel.kt
11d10
< import com.samourai.wallet.util.network.WebUtil
33d31
< private val _explorer = MutableLiveData("")
39d36
< val explorer: LiveData<String> get() = _explorer
49,52d45
< val explorerPayload = JSONObject(code).getJSONObject("explorer");
< if (explorerPayload.has("url")) {
< _explorer.postValue(explorerPayload.getString("url"))
< }
61,64d53
< }
< val dojoExplorer = JSONObject(code).getJSONObject("explorer");
< if (dojoExplorer.has("url")) {
< PrefsUtil.getInstance(applicationContext).setValue(PrefsUtil.BLOCK_EXPLORER_URL, dojoExplorer.getString("url"));
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/pairing/PairingMenu.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/pairing/PairingMenu.kt
27d26
< window.statusBarColor = resources.getColor(R.color.grey_accent)
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/payload/ExternalBackupManager.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/payload/ExternalBackupManager.kt
39c39
< private const val strBackupFilename = "ashigaru.txt"
---
> private const val strBackupFilename = "samourai.txt"
87c87,90
< }.setCancelable(false).show()
---
> }.setNegativeButton(R.string.cancel) { dialog, _ ->
> dialog.dismiss()
> Toast.makeText(appContext, "Read and write permissions are needed to save backup file", Toast.LENGTH_LONG).show()
> }.show()
245,249d247
< }
<
< @JvmStatic
< fun hasBackUpURI(): Boolean {
< return getBackUpURI() != null;
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/payload/PayloadUtil.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/payload/PayloadUtil.java
3,4d2
< import static com.samourai.wallet.send.SendActivity.SPEND_BOLTZMANN;
<
12d9
< import com.samourai.wallet.BuildConfig;
20d16
< import com.samourai.wallet.constants.WALLET_INDEX;
24a21
> import com.samourai.wallet.constants.WALLET_INDEX;
32a30,32
> import com.samourai.wallet.util.func.AddressFactory;
> import com.samourai.wallet.util.tech.AppUtil;
> import com.samourai.wallet.util.func.BatchSendUtil;
36,37c36
< import com.samourai.wallet.util.func.AddressFactory;
< import com.samourai.wallet.util.func.BatchSendUtil;
---
> import com.samourai.wallet.util.network.SIMUtil;
40,41d38
< import com.samourai.wallet.util.network.SIMUtil;
< import com.samourai.wallet.util.tech.AppUtil;
73a71,72
> import static com.samourai.wallet.send.SendActivity.SPEND_BOLTZMANN;
>
82c81
< private final static String strPayNymFilename = "ashigaru.paynyms";
---
> private final static String strPayNymFilename = "samourai.paynyms";
84c83
< private final static String strOptionalFilename = "ashigaru.rs.txt";
---
> private final static String strOptionalFilename = "samourai.support.txt";
227c226
< final JSONObject wallet = new JSONObject();
---
> JSONObject wallet = new JSONObject();
231,235c230,232
< final HD_Wallet hdWallet = HD_WalletFactory.getInstance(context).get();
< if (hdWallet != null) {
< if(hdWallet.getSeedHex() != null) {
< wallet.put("seed", hdWallet.getSeedHex());
< wallet.put("passphrase", hdWallet.getPassphrase());
---
> if(HD_WalletFactory.getInstance(context).get().getSeedHex() != null) {
> wallet.put("seed", HD_WalletFactory.getInstance(context).get().getSeedHex());
> wallet.put("passphrase", HD_WalletFactory.getInstance(context).get().getPassphrase());
237,241c234
< wallet.put("fingerprint", Hex.toHexString(HD_WalletFactory.getInstance(context).getFingerprint()));
< }
< final JSONArray accts = new JSONArray();
< accts.put(hdWallet.getAccount(0).toJSON(44));
< wallet.put("accounts", accts);
---
> wallet.put("fingerprint", Hex.toHexString(HD_WalletFactory.getInstance(context).getFingerprint()));
243a237,239
> JSONArray accts = new JSONArray();
> accts.put(HD_WalletFactory.getInstance(context).get().getAccount(0).toJSON(44));
> wallet.put("accounts", accts);
289c285
< meta.put("version_name", BuildConfig.VERSION_NAME);
---
> meta.put("version_name", context.getText(R.string.version_name));
350,353d345
< meta.put("explorer_url", PrefsUtil.getInstance(context).getValue(PrefsUtil.BLOCK_EXPLORER_URL, ""));
< if (PrefsUtil.getInstance(context).getValue(PrefsUtil.WALLET_SCAN_COMPLETE, false)) {
< meta.put("wallet_scan_complete", true);
< }
431,434c423
< synchronized public HD_Wallet restoreWalletfromJSON(
< final JSONObject obj,
< final boolean skipDojo
< ) throws DecoderException, MnemonicException.MnemonicLengthException {
---
> synchronized public HD_Wallet restoreWalletfromJSON(JSONObject obj,boolean skipDojo) throws DecoderException, MnemonicException.MnemonicLengthException {
468c457,458
< if (wallet.has("testnet")) {
---
>
> if(wallet.has("testnet")) {
471c461,462
< } else {
---
> }
> else {
475,482d465
< }
<
< if (meta != null) {
< // dojo should be set before set hdwallet which will start webservice
< if(!skipDojo && meta.has("dojo")) {
< DojoUtil.getInstance(context).fromJSON(meta.getJSONObject("dojo"));
< }
< }
484d466
< if(wallet != null) {
501a484
>
695a679,682
> if(!skipDojo)
> if (meta.has("dojo")) {
> DojoUtil.getInstance(context).fromJSON(meta.getJSONObject("dojo"));
> }
708,713d694
< if (meta.has("explorer_url") && PrefsUtil.getInstance(context).getValue(PrefsUtil.BLOCK_EXPLORER_URL, "").isEmpty()) {
< PrefsUtil.getInstance(context).setValue(PrefsUtil.BLOCK_EXPLORER_URL, meta.getString("explorer_url"));
< }
< if (meta.has("wallet_scan_complete")) {
< PrefsUtil.getInstance(context).setValue(PrefsUtil.WALLET_SCAN_COMPLETE, meta.getBoolean("wallet_scan_complete"));
< }
1042,1054c1023,1033
< final List<String> pcodes = Lists.newArrayList();
< try {
< String backupData = ExternalBackupManager.read();
< if (backupData != null) {
< try {
< String passphrase = HD_WalletFactory.getInstance(context).get().getPassphrase();
< String decrypted = getDecryptedBackupPayload(backupData, new CharSequenceX(passphrase));
< JSONObject json = new JSONObject(decrypted);
< JSONArray pCodes = json.getJSONObject("meta").getJSONObject("bip47").getJSONArray("pcodes");
< for (int i = 0; i < pCodes.length(); i++) {
< if (pCodes.getJSONObject(i).has("following")) {
< pcodes.add(String.valueOf(pCodes.getJSONObject(i).get("payment_code")));
< }
---
> String backupData = ExternalBackupManager.read();
> List<String> pcodes = Lists.newArrayList();
> if (backupData != null) {
> try {
> String passphrase = HD_WalletFactory.getInstance(context).get().getPassphrase();
> String decrypted = getDecryptedBackupPayload(backupData, new CharSequenceX(passphrase));
> JSONObject json = new JSONObject(decrypted);
> JSONArray pCodes = json.getJSONObject("meta").getJSONObject("bip47").getJSONArray("pcodes");
> for (int i = 0; i < pCodes.length(); i++) {
> if (pCodes.getJSONObject(i).has("following")) {
> pcodes.add(String.valueOf(pCodes.getJSONObject(i).get("payment_code")));
1056,1057d1034
< } catch (Exception e) {
< System.out.println("Something went wrong: " + e);
1058a1036,1037
> } catch (Exception e) {
> System.out.println("Something went wrong: "+ e);
1060,1061d1038
< } catch (final Exception e1) {
< System.out.println("No backup file found for Paynyms: "+ e1);
1063d1039
<
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/addPaynym/AddPaynymActivity.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/addPaynym/AddPaynymActivity.java
56d55
< getWindow().setStatusBarColor(getResources().getColor(R.color.grey_accent));
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/api/PayNymApiService.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/api/PayNymApiService.kt
4c4,5
< import android.util.Log
---
> import com.samourai.wallet.access.AccessFactory
> import com.samourai.wallet.api.APIFactory
5a7
> import com.samourai.wallet.bip47.BIP47Meta
7c9,13
< import com.samourai.wallet.sync.SyncWalletModel
---
> import com.samourai.wallet.bip47.rpc.NotSecp256k1Exception
> import com.samourai.wallet.bip47.rpc.PaymentCode
> import com.samourai.wallet.crypto.DecryptionException
> import com.samourai.wallet.payload.PayloadUtil
> import com.samourai.wallet.util.CharSequenceX
9d14
< import com.samourai.wallet.util.func.synPayNym
11,14c16
< import okhttp3.HttpUrl
< import okhttp3.OkHttpClient
< import okhttp3.Request
< import okhttp3.RequestBody
---
> import okhttp3.*
16c18,19
< import okhttp3.Response
---
> import org.bitcoinj.crypto.MnemonicException
> import org.json.JSONException
18a22,25
> import java.security.InvalidKeyException
> import java.security.NoSuchAlgorithmException
> import java.security.NoSuchProviderException
> import java.security.spec.InvalidKeySpecException
27,28d33
< private val TAG = PayNymApiService::class.java.simpleName
<
181c186
< suspend fun unfollow(pcode: String): Response {
---
> public suspend fun unfollow(pcode: String): Response {
199,207d203
< fun syncPcode(pcode: String): Boolean {
< try {
< synPayNym(pcode, context)
< return true
< } catch (ex: Exception) {
< Log.e(TAG, "Exception on synPayNym")
< }
< return false
< }
209c205
< suspend fun retrievePayNymConnections(): Boolean {
---
> fun syncPcode(pcode: String) {
211c207,259
< return SyncWalletModel.retrievePayNymConnections(context)
---
> val payment_code = PaymentCode(pcode)
> var idx = 0
> var loop = true
> val addrs = ArrayList<String>()
> while (loop) {
> addrs.clear()
> for (i in idx until idx + 20) {
> // Log.i("BIP47Activity", "sync receive from " + i + ":" + BIP47Util.getInstance(BIP47Activity.this).getReceivePubKey(payment_code, i));
> BIP47Meta.getInstance().idx4AddrLookup[BIP47Util.getInstance(context).getReceivePubKey(payment_code, i)] = i
> BIP47Meta.getInstance().pCode4AddrLookup[BIP47Util.getInstance(context).getReceivePubKey(payment_code, i)] = payment_code.toString()
> addrs.add(BIP47Util.getInstance(context).getReceivePubKey(payment_code, i))
> // Log.i("BIP47Activity", "p2pkh " + i + ":" + BIP47Util.getInstance(BIP47Activity.this).getReceiveAddress(payment_code, i).getReceiveECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString());
> }
> val s = addrs.toTypedArray()
> val nb = APIFactory.getInstance(context).syncBIP47Incoming(s)
> // Log.i("BIP47Activity", "sync receive idx:" + idx + ", nb == " + nb);
> if (nb == 0) {
> loop = false
> }
> idx += 20
> }
> idx = 0
> loop = true
> BIP47Meta.getInstance().setOutgoingIdx(pcode, 0)
> while (loop) {
> addrs.clear()
> for (i in idx until idx + 20) {
> val sendAddress = BIP47Util.getInstance(context).getSendAddress(payment_code, i)
> // Log.i("BIP47Activity", "sync send to " + i + ":" + sendAddress.getSendECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString());
> // BIP47Meta.getInstance().setOutgoingIdx(payment_code.toString(), i);
> BIP47Meta.getInstance().idx4AddrLookup[BIP47Util.getInstance(context).getSendPubKey(payment_code, i)] = i
> BIP47Meta.getInstance().pCode4AddrLookup[BIP47Util.getInstance(context).getSendPubKey(payment_code, i)] = payment_code.toString()
> addrs.add(BIP47Util.getInstance(context).getSendPubKey(payment_code, i))
> }
> val s = addrs.toTypedArray()
> val nb = APIFactory.getInstance(context).syncBIP47Outgoing(s)
> // Log.i("BIP47Activity", "sync send idx:" + idx + ", nb == " + nb);
> if (nb == 0) {
> loop = false
> }
> idx += 20
> }
> BIP47Meta.getInstance().pruneIncoming()
> PayloadUtil.getInstance(context.applicationContext).saveWalletToJSON(CharSequenceX(AccessFactory.getInstance(context.applicationContext).guid + AccessFactory.getInstance(context.applicationContext).pin))
> } catch (ioe: IOException) {
> } catch (je: JSONException) {
> } catch (de: DecryptionException) {
> } catch (nse: NotSecp256k1Exception) {
> } catch (ikse: InvalidKeySpecException) {
> } catch (ike: InvalidKeyException) {
> } catch (nsae: NoSuchAlgorithmException) {
> } catch (nspe: NoSuchProviderException) {
> } catch (mle: MnemonicException.MnemonicLengthException) {
213d260
< Log.e(TAG, "Exception on synPayNym")
215d261
< return false
225c271
< const val PAYNYM_API = "https://paynym.rs/";
---
> const val PAYNYM_API = "https://paynym.is/";
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/fragments/EditPaynymBottomSheet.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/fragments/EditPaynymBottomSheet.java
28c28
< private TextInputEditText labelEdt;
---
> private TextInputEditText labelEdt, pcodeEdt;
30d29
< private MaterialButton removeNickBtn;
47a47
> pcodeEdt = view.findViewById(R.id.paynym_pcode);
49d48
< removeNickBtn = view.findViewById(R.id.remove_nickname_button);
51a51
> pcodeEdt.setText(pcode);
53,55d52
< removeNickBtn.setText("Delete nickname and save");
< if (getArguments().getString("nymName").equals(label))
< removeNickBtn.setVisibility(View.GONE);
62,69d58
<
< removeNickBtn.setOnClickListener(button -> {
< labelEdt.setText(getArguments().getString("nymName"));
< this.dismiss();
< if (onClickListener != null) {
< onClickListener.onClick(button);
< }
< });
73,75d61
< public String getPcode() {
< return pcode;
< }
78a65,68
> }
>
> public String getPcode() {
> return pcodeEdt.getText().toString();
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/fragments/PaynymListFragment.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/fragments/PaynymListFragment.java
3,5d2
< import static android.view.View.GONE;
< import static java.lang.String.format;
<
30,31d26
< import org.apache.commons.lang3.StringUtils;
<
105c100
<
---
> final String strPaymentCode = pcodes.get(position);
109d103
< final TextView paynymLabel = holder.paynymLabel;
111,116c105,139
< final String strPaymentCode = pcodes.get(position);
< if (strPaymentCode == null) {
< paynymCode.setText("");
< paynymLabel.setText("");
< avatar.setImageResource(R.drawable.paynym);
< return;
---
> try {
> Picasso.get().load(WebUtil.PAYNYM_API + strPaymentCode + "/avatar")
> .into(avatar, new Callback() {
> @Override
> public void onSuccess() {
> paynymCode.setText(BIP47Meta.getInstance().getDisplayLabel(strPaymentCode));
> itemView.setOnClickListener(view -> onPayNymItemClick(strPaymentCode, avatar, true));
> }
>
> @Override
> public void onError(Exception e) {
>
> Picasso.get().load(WebUtil.PAYNYM_API + "preview/" + strPaymentCode)
> .into(avatar, new Callback() {
> @Override
> public void onSuccess() {
> paynymCode.setText(BIP47Meta.getInstance().getDisplayLabel(strPaymentCode));
> itemView.setOnClickListener(view -> onPayNymItemClick(strPaymentCode, avatar, false));
> }
>
> @Override
> public void onError(final Exception e) {
> Log.e(TAG, "issue when loading avatar for " + strPaymentCode, e);
> }
> });
> }
> });
> } catch (final Throwable t) {
> /**
> * This catch block is useful if ever the onSuccess/onError callback system
> * throws a runtime exception.
> * It indicates a problem to be fixed, so we log in error.
> * This has already been the case through the method LogUtil#error.
> */
> Log.e(TAG, "error with Picasso: " + t.getMessage(), t);
118,121d140
<
< setPayNymLabels(strPaymentCode, paynymCode, paynymLabel);
< setPayNymLogos(strPaymentCode, avatar, itemView);
<
139d157
< TextView paynymLabel;
145d162
< paynymLabel = itemView.findViewById(R.id.paynym_label);
148,227d164
< }
<
< private static void setPayNymLabels(
< final String strPaymentCode,
< final TextView paynymCode,
< final TextView paynymLabel) {
<
< if (!StringUtils.equals(
< BIP47Meta.getInstance().getName(strPaymentCode),
< BIP47Meta.getInstance().getDisplayLabel(strPaymentCode))) {
<
< paynymCode.setText(BIP47Meta.getInstance().getName(strPaymentCode));
< paynymLabel.setText(BIP47Meta.getInstance().getDisplayLabel(strPaymentCode));
< paynymLabel.setVisibility(View.VISIBLE);
< } else {
< paynymCode.setText(BIP47Meta.getInstance().getName(strPaymentCode));
< paynymLabel.setText("");
< paynymLabel.setVisibility(GONE);
< }
< }
<
< private void setPayNymLogos(String strPaymentCode, CircleImageView avatar, View itemView) {
< try {
< Picasso.get().load(WebUtil.PAYNYM_API + strPaymentCode + "/avatar")
< .into(avatar, createPicassoCallback(itemView, strPaymentCode, avatar));
< } catch (final Throwable t) {
< /**
< * This catch block is useful if ever the onSuccess/onError callback system
< * throws a runtime exception.
< * It indicates a problem to be fixed, so we log in error.
< * This has already been the case through the method LogUtil#error.
< */
< Log.e(TAG, format("Throwable with Picasso on /avatar %s : %s", strPaymentCode, t.getMessage()), t);
< avatar.setImageResource(R.drawable.paynym);
< itemView.setOnClickListener(view -> onPayNymItemClick(strPaymentCode, avatar, false));
< }
< }
<
< @NonNull
< private Callback createPicassoCallback(
< final View itemView,
< final String strPaymentCode,
< final CircleImageView avatar) {
< return new Callback() {
< @Override
< public void onSuccess() {
< itemView.setOnClickListener(view -> onPayNymItemClick(strPaymentCode, avatar, true));
< }
<
< @Override
< public void onError(Exception e) {
<
< try {
< Picasso.get().load(WebUtil.PAYNYM_API + "preview/" + strPaymentCode)
< .into(avatar, new Callback() {
< @Override
< public void onSuccess() {
< itemView.setOnClickListener(view -> onPayNymItemClick(strPaymentCode, avatar, false));
< }
<
< @Override
< public void onError(final Exception e) {
< Log.e(TAG, "issue when loading avatar for " + strPaymentCode, e);
< avatar.setImageResource(R.drawable.paynym);
< itemView.setOnClickListener(view -> onPayNymItemClick(strPaymentCode, avatar, false));
< }
< });
< } catch (final Throwable t) {
< /**
< * This catch block is useful if ever the onSuccess/onError callback system
< * throws a runtime exception.
< * It indicates a problem to be fixed, so we log in error.
< * This has already been the case through the method LogUtil#error.
< */
< Log.e(TAG, format("Throwable with Picasso on /preview %s : %s", strPaymentCode, t.getMessage()), t);
< avatar.setImageResource(R.drawable.paynym);
< itemView.setOnClickListener(view -> onPayNymItemClick(strPaymentCode, avatar, false));
< }
< }
< };
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/paynymDetails/PayNymDetailsActivity.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/paynymDetails/PayNymDetailsActivity.kt
6a7
> import android.net.Uri
7a9
> import android.os.Looper
28d29
< import com.samourai.wallet.SamouraiWalletConst
59a61
> import com.samourai.wallet.tor.SamouraiTorManager
65a68
> import com.samourai.wallet.util.func.RBFFactory.updateRBFSpendForBroadcastTxAndRegister
69a73,74
> import com.samourai.wallet.xmanagerClient.XManagerClient
> import com.samourai.xmanager.protocol.XManagerService
79d83
< import kotlinx.coroutines.async
81,83d84
< import kotlinx.coroutines.runBlocking
< import kotlinx.coroutines.withContext
< import org.apache.commons.lang3.StringUtils.isNotBlank
122d122
< window.statusBarColor = resources.getColor(R.color.grey_accent)
168,189d167
< if (isNotBlank(pcode) && !BIP47Meta.getInstance().isFollowing(pcode)) {
< val disposable = Observable.fromCallable<Boolean> {
<
< runBlocking {
< withContext(Dispatchers.IO) {
< async {
< payNymViewModel.doFollow(pcode!!)
< }.await()
< async {
< payNymViewModel.getPayNymData()
< }.await()
< }
< }
< true
< }.subscribeOn(Schedulers.io())
< .observeOn(AndroidSchedulers.mainThread())
< .subscribe { status: Boolean ->
< Log.i(TAG, "auto follow an already connected PayNym")
< }
< disposables.add(disposable)
< return
< }
211c189
< binding.txtviewPaynym.text = getName()
---
> title = getLabel()
350,369c328
< pcode?.let {
<
< val disposable = Observable.fromCallable<Boolean> {
<
< runBlocking {
< withContext(Dispatchers.IO) {
< async {
< payNymViewModel.doFollow(it)
< }.await()
< }
< }
< true
< }.subscribeOn(Schedulers.io())
< .observeOn(AndroidSchedulers.mainThread())
< .subscribe { status: Boolean ->
< Log.i(TAG, "follow a PayNym")
< }
< disposables.add(disposable)
<
< }
---
> pcode?.let { payNymViewModel.doFollow(it) };
382,387d340
< private fun getName(): String {
< if (pcode == BIP47Meta.strSamouraiDonationPCode && SamouraiWallet.getInstance().isTestNet) return "+ashigarutest"
< if (pcode == BIP47Meta.strSamouraiDonationPCode && !SamouraiWallet.getInstance().isTestNet) return "+ashigaru"
< return BIP47Meta.getInstance().getName(pcode)
< }
<
449c402
< Snackbar.make(findViewById(android.R.id.content), "Follow transaction is still pending", Snackbar.LENGTH_SHORT).show()
---
> Snackbar.make(binding.historyLayout.rootView, "Follow transaction is still pending", Snackbar.LENGTH_SHORT).show()
456d408
< bundle.putString("nymName", getName())
510c462
< Snackbar.make(findViewById(android.R.id.content), R.string.invalid_payment_code, Snackbar.LENGTH_SHORT).show()
---
> Snackbar.make(binding.userAvatar.rootView, R.string.invalid_payment_code, Snackbar.LENGTH_SHORT).show()
512c464
< Snackbar.make(findViewById(android.R.id.content), R.string.bip47_no_label_error, Snackbar.LENGTH_SHORT).show()
---
> Snackbar.make(binding.userAvatar.rootView, R.string.bip47_no_label_error, Snackbar.LENGTH_SHORT).show()
515c467,468
< scope.launch(Dispatchers.IO) {
---
> Thread {
> Looper.prepare()
535a489
> } finally {
537,540c491,493
< scope.launch(Dispatchers.Main) {
< doUpdatePayNymInfo(pcode)
< }
< }
---
> Looper.loop()
> doUpdatePayNymInfo(pcode)
> }.start()
560a514
>
564,571c518,538
< try {
< doNotifyTxAsync()
< } catch (t : Throwable) {
< manageException(t)
< }
< }
< return
< }
---
> val httpClient: IHttpClient = AndroidHttpClient(com.samourai.wallet.util.network.WebUtil.getInstance(applicationContext))
> val xManagerClient = XManagerClient(httpClient, SamouraiWallet.getInstance().isTestNet, SamouraiTorManager.isConnected())
> val address = xManagerClient.getAddressOrDefault(XManagerService.BIP47)
> SendNotifTxFactory.getInstance().setAddress(address)
> //
> // get wallet balance
> //
> var balance = 0L
> balance = try {
> APIFactory.getInstance(this@PayNymDetailsActivity).xpubAmounts[HD_WalletFactory.getInstance(this@PayNymDetailsActivity).get().getAccount(0).xpubstr()]!!
> } catch (npe: NullPointerException) {
> 0L
> }
> val selectedUTXO: MutableList<UTXO?> = ArrayList()
> var totalValueSelected = 0L
> // long change = 0L;
> var fee: BigInteger? = null
> //
> // spend dust threshold amount to notification address
> //
> var amount = SendNotifTxFactory._bNotifTxValue.toLong()
573c540,543
< private fun doNotifyTxAsync() {
---
> //
> // add Samourai Wallet fee to total amount
> //
> amount += SendNotifTxFactory._bSWFee.toLong()
575,596c545,554
< val selectedUTXO: MutableList<UTXO?> = ArrayList()
< var totalValueSelected = 0L
< val fee: BigInteger?
<
< // spend dust threshold amount to notification address
< val amount = SendNotifTxFactory._bNotifTxValue.toLong()
<
< // add Ashigaru fee to total amount
< //amount += SendNotifTxFactory._bSWFee.toLong()
<
< // get unspents
< var utxos: MutableList<UTXO?>?
< if (UTXOFactory.getInstance().totalP2SH_P2WPKH > amount + FeeUtil.getInstance()
< .estimatedFeeSegwit(0, 1, 0, 4).toLong()
< ) {
< utxos = ArrayList()
< utxos.addAll(
< APIFactory.getInstance(this@PayNymDetailsActivity).getUtxosP2SH_P2WPKH(true)
< )
< } else {
< utxos = APIFactory.getInstance(this@PayNymDetailsActivity).getUtxos(true)
< }
---
> //
> // get unspents
> //
> var utxos: MutableList<UTXO?>? = null
> if (UTXOFactory.getInstance().totalP2SH_P2WPKH > amount + FeeUtil.getInstance().estimatedFeeSegwit(0, 1, 0, 4).toLong()) {
> utxos = ArrayList()
> utxos.addAll(APIFactory.getInstance(this@PayNymDetailsActivity).getUtxosP2SH_P2WPKH(true))
> } else {
> utxos = APIFactory.getInstance(this@PayNymDetailsActivity).getUtxos(true)
> }
598,601c556,559
< // sort in ascending order by value
< val _utxos: List<UTXO?>? = utxos
< Collections.sort(_utxos, UTXOComparator())
< Collections.reverse(_utxos)
---
> // sort in ascending order by value
> val _utxos: List<UTXO?>? = utxos
> Collections.sort(_utxos, UTXOComparator())
> Collections.reverse(_utxos)
603,607c561,566
< // get smallest 1 UTXO > than spend + fee + sw fee + dust
< for (u in _utxos!!) {
< if (u!!.value >= amount + SamouraiWallet.bDust.toLong() + FeeUtil.getInstance()
< .estimatedFee(1, 4).toLong()
< ) {
---
> //
> // get smallest 1 UTXO > than spend + fee + sw fee + dust
> //
> for (u in _utxos!!) {
> if (u!!.value >= amount + SamouraiWallet.bDust.toLong() + FeeUtil.getInstance()
> .estimatedFee(1, 4).toLong()) {
609,614c568,574
< selectedUTXO.add(u)
< totalValueSelected += u.value
< Log.d("PayNymDetailsActivity", "value selected:" + u.value)
< Log.d("PayNymDetailsActivity", "total value selected:$totalValueSelected")
< Log.d("PayNymDetailsActivity", "nb inputs:" + u.outpoints.size)
< break
---
> selectedUTXO.add(u)
> totalValueSelected += u.value
> Log.d("PayNymDetailsActivity", "value selected:" + u.value)
> Log.d("PayNymDetailsActivity", "total value selected:$totalValueSelected")
> Log.d("PayNymDetailsActivity", "nb inputs:" + u.outpoints.size)
> break
> }
616d575
< }
618,620c577,581
< val outputCountForFeeEstimation =
< if (FeeUtil.getInstance().feeRepresentation === EnumFeeRepresentation.BLOCK_COUNT) 6
< else 3
---
> val keepCurrentSuggestedFee = FeeUtil.getInstance().suggestedFee
> try {
> if (FeeUtil.getInstance().feeRepresentation === EnumFeeRepresentation.NEXT_BLOCK_RATE) {
> FeeUtil.getInstance().suggestedFee = FeeUtil.getInstance().highFee
> } else {
622,626c583,595
< val keepCurrentSuggestedFee = FeeUtil.getInstance().suggestedFee
< try {
< if (FeeUtil.getInstance().feeRepresentation === EnumFeeRepresentation.NEXT_BLOCK_RATE) {
< FeeUtil.getInstance().suggestedFee = FeeUtil.getInstance().highFee
< } else {
---
> val lo = FeeUtil.getInstance().lowFee.defaultPerKB.toLong() / 1000L
> val mi = FeeUtil.getInstance().normalFee.defaultPerKB.toLong() / 1000L
> val hi = FeeUtil.getInstance().highFee.defaultPerKB.toLong() / 1000L
> if (lo == mi && mi == hi) {
> val hi_sf = SuggestedFee()
> hi_sf.defaultPerKB = BigInteger.valueOf((hi * 1000.0 * 1.15).toLong())
> FeeUtil.getInstance().suggestedFee = hi_sf
> } else if (lo == mi) {
> FeeUtil.getInstance().suggestedFee = FeeUtil.getInstance().highFee
> } else {
> FeeUtil.getInstance().suggestedFee = FeeUtil.getInstance().normalFee
> }
> }
628,636c597,616
< val lo = FeeUtil.getInstance().lowFee.defaultPerKB.toLong() / 1000L
< val mi = FeeUtil.getInstance().normalFee.defaultPerKB.toLong() / 1000L
< val hi = FeeUtil.getInstance().highFee.defaultPerKB.toLong() / 1000L
< if (lo == mi && mi == hi) {
< val hi_sf = SuggestedFee()
< hi_sf.defaultPerKB = BigInteger.valueOf((hi * 1000.0 * 1.15).toLong())
< FeeUtil.getInstance().suggestedFee = hi_sf
< } else if (lo == mi) {
< FeeUtil.getInstance().suggestedFee = FeeUtil.getInstance().highFee
---
>
> if (selectedUTXO.size == 0) {
> // sort in descending order by value
> Collections.sort(_utxos, UTXOComparator())
> var selected = 0
>
> // get largest UTXOs > than spend + fee + dust
> for (u in _utxos) {
> selectedUTXO.add(u)
> totalValueSelected += u!!.value
> selected += u.outpoints.size
> if (totalValueSelected >= amount + SamouraiWallet.bDust.toLong() + FeeUtil.getInstance().estimatedFee(selected, 4).toLong()) {
> Log.d("PayNymDetailsActivity", "multiple outputs")
> Log.d("PayNymDetailsActivity", "total value selected:$totalValueSelected")
> Log.d("PayNymDetailsActivity", "nb inputs:" + u.outpoints.size)
> break
> }
> }
>
> fee = FeeUtil.getInstance().estimatedFee(selected, 7)
638c618
< FeeUtil.getInstance().suggestedFee = FeeUtil.getInstance().normalFee
---
> fee = FeeUtil.getInstance().estimatedFee(1, 7)
639a620,623
> } catch(e : Exception) {
> return@launch
> } finally {
> FeeUtil.getInstance().suggestedFee = keepCurrentSuggestedFee
641,644d624
< if (selectedUTXO.size == 0) {
< // sort in descending order by value
< Collections.sort(_utxos, UTXOComparator())
< var selected = 0
646,657c626,647
< // get largest UTXOs > than spend + fee + dust
< for (u in _utxos) {
< selectedUTXO.add(u)
< totalValueSelected += u!!.value
< selected += u.outpoints.size
< if (totalValueSelected >= amount + SamouraiWallet.bDust.toLong() + FeeUtil.getInstance()
< .estimatedFee(selected, 4).toLong()
< ) {
< Log.d("PayNymDetailsActivity", "multiple outputs")
< Log.d("PayNymDetailsActivity", "total value selected:$totalValueSelected")
< Log.d("PayNymDetailsActivity", "nb inputs:" + u.outpoints.size)
< break
---
> //
> // total amount to spend including fee
> //
> if (amount + fee!!.toLong() >= balance) {
> scope.launch(Dispatchers.Main) {
> binding.progressBar.visibility = View.INVISIBLE
> var message: String? = getText(R.string.bip47_notif_tx_insufficient_funds_1).toString() + " "
> val biAmount = SendNotifTxFactory._bSWFee.add(SendNotifTxFactory._bNotifTxValue.add(FeeUtil.getInstance().estimatedFee(1, 4, FeeUtil.getInstance().lowFee.defaultPerKB)))
> val strAmount = FormatsUtil.formatBTC(biAmount.toLong());
> message += strAmount
> message += " " + getText(R.string.bip47_notif_tx_insufficient_funds_2)
> val dlg = MaterialAlertDialogBuilder(this@PayNymDetailsActivity)
> .setTitle(R.string.app_name)
> .setMessage(message)
> .setCancelable(false)
> .setPositiveButton(R.string.help) { _, _ ->
> val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://docs.samourai.io/wallet/usage#follow-paynyms"))
> startActivity(browserIntent)
> }
> .setNegativeButton(R.string.close) { _, _ -> }
> if (!isFinishing) {
> dlg.show()
659a650,651
> return@launch
> }
661,663c653,663
< fee = FeeUtil.getInstance().estimatedFee(selected, outputCountForFeeEstimation)
< } else {
< fee = FeeUtil.getInstance().estimatedFee(1, outputCountForFeeEstimation)
---
> //
> // payment code to be notified
> //
> val payment_code: PaymentCode?
> payment_code = try {
> PaymentCode(pcode)
> } catch (afe: AddressFormatException) {
> null
> }
> if (payment_code == null) {
> return@launch
665,669d664
< } catch (e: Exception) {
< return
< } finally {
< FeeUtil.getInstance().suggestedFee = keepCurrentSuggestedFee
< }
671,691c666,681
< //
< // total amount to spend including fee
< //
< val toSpent = amount + fee!!.toLong()
< val balance = APIFactory.getInstance(this@PayNymDetailsActivity).xpubBalance
< if (toSpent >= balance || toSpent >= totalValueSelected) {
< scope.launch(Dispatchers.Main) {
< binding.progressBar.visibility = View.INVISIBLE
< var message: String? =
< getText(R.string.bip47_notif_tx_insufficient_funds_1).toString() + " "
< val biAmount = BigInteger.valueOf(toSpent)
< val strAmount = FormatsUtil.formatBTC(biAmount.toLong());
< message += strAmount
< message += " " + getText(R.string.bip47_notif_tx_insufficient_funds_2)
< val dlg = MaterialAlertDialogBuilder(this@PayNymDetailsActivity)
< .setTitle(R.string.app_name)
< .setMessage(message)
< .setCancelable(false)
< .setPositiveButton(R.string.close) { _, _ -> }
< if (!isFinishing) {
< dlg.show()
---
> //
> // create outpoints for spend later
> //
> val outpoints: MutableList<MyTransactionOutPoint> = ArrayList()
> for (u in selectedUTXO) {
> outpoints.addAll(u!!.outpoints)
> }
> //
> // create inputs from outpoints
> //
> val inputs: MutableList<MyTransactionInput> = ArrayList()
> val currentNetworkParams = SamouraiWallet.getInstance().currentNetworkParams
> for (o in outpoints) {
> val script = Script(o.scriptBytes)
> if (script.scriptType == Script.ScriptType.NO_TYPE) {
> continue
692a683,684
> val input = MyTransactionInput(currentNetworkParams, null, ByteArray(0), o, o.txHash.toString(), o.txOutputN)
> inputs.add(input)
694,765c686,698
< return
< }
<
< //
< // payment code to be notified
< //
< val payment_code: PaymentCode?
< payment_code = try {
< PaymentCode(pcode)
< } catch (afe: AddressFormatException) {
< null
< }
< if (payment_code == null) {
< return
< }
<
< //
< // create outpoints for spend later
< //
< val outpoints: MutableList<MyTransactionOutPoint> = ArrayList()
< for (u in selectedUTXO) {
< outpoints.addAll(u!!.outpoints)
< }
< //
< // create inputs from outpoints
< //
< val inputs: MutableList<MyTransactionInput> = ArrayList()
< val currentNetworkParams = SamouraiWallet.getInstance().currentNetworkParams
< for (o in outpoints) {
< val script = Script(o.scriptBytes)
< if (script.scriptType == Script.ScriptType.NO_TYPE) {
< continue
< }
< val input = MyTransactionInput(
< currentNetworkParams,
< null,
< ByteArray(0),
< o,
< o.txHash.toString(),
< o.txOutputN
< )
< inputs.add(input)
< }
< //
< // sort inputs
< //
< Collections.sort(inputs, SendFactory.BIP69InputComparator())
< //
< // find outpoint that corresponds to 0th input
< //
< var outPoint: MyTransactionOutPoint? = null
< for (o in outpoints) {
< if (o.txHash.toString() == inputs[0].getTxHash() && o.txOutputN == inputs[0].getTxPos()) {
< outPoint = o
< break
< }
< }
< if (outPoint == null) {
< throw Exception(getString(R.string.bip47_cannot_identify_outpoint))
< }
< var op_return: ByteArray? = null
< //
< // get private key corresponding to outpoint
< //
< try {
< // Script inputScript = new Script(outPoint.getConnectedPubKeyScript());
< val scriptBytes = outPoint?.connectedPubKeyScript
< var address: String?
< address = if (Bech32Util.getInstance().isBech32Script(Hex.toHexString(scriptBytes))) {
< Bech32Util.getInstance().getAddressFromScript(Hex.toHexString(scriptBytes))
< } else {
< Script(scriptBytes).getToAddress(currentNetworkParams).toString()
---
> //
> // sort inputs
> //
> Collections.sort(inputs, SendFactory.BIP69InputComparator())
> //
> // find outpoint that corresponds to 0th input
> //
> var outPoint: MyTransactionOutPoint? = null
> for (o in outpoints) {
> if (o.txHash.toString() == inputs[0].getTxHash() && o.txOutputN == inputs[0].getTxPos()) {
> outPoint = o
> break
> }
767,770c700,701
< // String address = inputScript.getToAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
< val ecKey = SendFactory.getPrivKey(address, 0)
< if (ecKey == null || !ecKey.hasPrivKey()) {
< throw Exception(getString(R.string.bip47_cannot_compose_notif_tx))
---
> if (outPoint == null) {
> throw Exception(getString(R.string.bip47_cannot_identify_outpoint))
772c703
<
---
> var op_return: ByteArray? = null
774c705
< // use outpoint for payload masking
---
> // get private key corresponding to outpoint
776,803c707,748
< val privkey = ecKey.privKeyBytes
< val pubkey = payment_code.notificationAddress(currentNetworkParams).pubKey
< val outpoint = outPoint?.bitcoinSerialize()
< // Log.i("PayNymDetailsActivity", "outpoint:" + Hex.toHexString(outpoint));
< // Log.i("PayNymDetailsActivity", "payer shared secret:" + Hex.toHexString(new SecretPoint(privkey, pubkey).ECDHSecretAsBytes()));
< val mask =
< PaymentCode.getMask(SecretPoint(privkey, pubkey).ECDHSecretAsBytes(), outpoint)
< // Log.i("PayNymDetailsActivity", "mask:" + Hex.toHexString(mask));
< // Log.i("PayNymDetailsActivity", "mask length:" + mask.length);
< // Log.i("PayNymDetailsActivity", "payload0:" + Hex.toHexString(BIP47Util.getInstance(context).getPaymentCode().getPayload()));
< op_return = PaymentCode.blind(
< BIP47Util.getInstance(this@PayNymDetailsActivity).paymentCode.payload,
< mask
< )
< // Log.i("PayNymDetailsActivity", "payload1:" + Hex.toHexString(op_return));
< } catch (ike: InvalidKeyException) {
< throw ike
< } catch (ikse: InvalidKeySpecException) {
< throw ikse
< } catch (nsae: NoSuchAlgorithmException) {
< throw nsae
< } catch (nspe: NoSuchProviderException) {
< throw nspe
< } catch (e: Exception) {
< throw e
< }
< val receivers = HashMap<String, BigInteger>()
< receivers[Hex.toHexString(op_return)] = BigInteger.ZERO
---
> try {
> // Script inputScript = new Script(outPoint.getConnectedPubKeyScript());
> val scriptBytes = outPoint?.connectedPubKeyScript
> var address: String?
> address = if (Bech32Util.getInstance().isBech32Script(Hex.toHexString(scriptBytes))) {
> Bech32Util.getInstance().getAddressFromScript(Hex.toHexString(scriptBytes))
> } else {
> Script(scriptBytes).getToAddress(currentNetworkParams).toString()
> }
> // String address = inputScript.getToAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
> val ecKey = SendFactory.getPrivKey(address, 0)
> if (ecKey == null || !ecKey.hasPrivKey()) {
> throw Exception(getString(R.string.bip47_cannot_compose_notif_tx))
> }
>
> //
> // use outpoint for payload masking
> //
> val privkey = ecKey.privKeyBytes
> val pubkey = payment_code.notificationAddress(currentNetworkParams).pubKey
> val outpoint = outPoint?.bitcoinSerialize()
> // Log.i("PayNymDetailsActivity", "outpoint:" + Hex.toHexString(outpoint));
> // Log.i("PayNymDetailsActivity", "payer shared secret:" + Hex.toHexString(new SecretPoint(privkey, pubkey).ECDHSecretAsBytes()));
> val mask = PaymentCode.getMask(SecretPoint(privkey, pubkey).ECDHSecretAsBytes(), outpoint)
> // Log.i("PayNymDetailsActivity", "mask:" + Hex.toHexString(mask));
> // Log.i("PayNymDetailsActivity", "mask length:" + mask.length);
> // Log.i("PayNymDetailsActivity", "payload0:" + Hex.toHexString(BIP47Util.getInstance(context).getPaymentCode().getPayload()));
> op_return = PaymentCode.blind(BIP47Util.getInstance(this@PayNymDetailsActivity).paymentCode.payload, mask)
> // Log.i("PayNymDetailsActivity", "payload1:" + Hex.toHexString(op_return));
> } catch (ike: InvalidKeyException) {
> throw ike
> } catch (ikse: InvalidKeySpecException) {
> throw ikse
> } catch (nsae: NoSuchAlgorithmException) {
> throw nsae
> } catch (nspe: NoSuchProviderException) {
> throw nspe
> } catch (e: Exception) {
> throw e
> }
> val receivers = HashMap<String, BigInteger>()
> receivers[Hex.toHexString(op_return)] = BigInteger.ZERO
805,806c750
< val notificationAddr = payment_code.notificationAddress(currentNetworkParams).addressString
< /*
---
> val notificationAddr = payment_code.notificationAddress(currentNetworkParams).addressString
810d753
< */
812,813c755,756
< receivers[notificationAddr] = SendNotifTxFactory._bNotifTxValue
< //receivers[samFeeAddress] = SendNotifTxFactory._bSWFee
---
> receivers[notificationAddr] = SendNotifTxFactory._bNotifTxValue
> receivers[samFeeAddress] = SendNotifTxFactory._bSWFee
815,839c758,776
< val change = totalValueSelected - (amount + fee.toLong())
< if (change > 0L) {
< val change_address = BIP84Util.getInstance(this@PayNymDetailsActivity).getAddressAt(
< AddressFactory.CHANGE_CHAIN,
< BIP84Util.getInstance(this@PayNymDetailsActivity).wallet.getAccount(0).change.addrIdx
< ).bech32AsString
< receivers[change_address] = BigInteger.valueOf(change)
< }
< Log.d("PayNymDetailsActivity", "outpoints:" + outpoints.size)
< Log.d(
< "PayNymDetailsActivity",
< "totalValueSelected:" + BigInteger.valueOf(totalValueSelected).toString()
< )
< Log.d("PayNymDetailsActivity", "amount:" + BigInteger.valueOf(amount).toString())
< Log.d("PayNymDetailsActivity", "change:" + BigInteger.valueOf(change).toString())
< Log.d("PayNymDetailsActivity", "fee:$fee")
< if (change < 0L) {
< throw Exception(getString(R.string.bip47_cannot_compose_notif_tx))
< }
< val _outPoint: MyTransactionOutPoint = outPoint!!
< var strNotifTxMsg = getText(R.string.bip47_setup4_text1).toString() + " "
< val notifAmount = amount
< val strAmount =
< MonetaryUtil.getInstance().btcFormat.format((notifAmount.toDouble() + fee.toLong()) / 1e8) + " BTC "
< strNotifTxMsg += strAmount + getText(R.string.bip47_setup4_text2)
---
> val change = totalValueSelected - (amount + fee.toLong())
> if (change > 0L) {
> val change_address = BIP84Util.getInstance(this@PayNymDetailsActivity).getAddressAt(
> AddressFactory.CHANGE_CHAIN, BIP84Util.getInstance(this@PayNymDetailsActivity).wallet.getAccount(0).change.addrIdx).bech32AsString
> receivers[change_address] = BigInteger.valueOf(change)
> }
> Log.d("PayNymDetailsActivity", "outpoints:" + outpoints.size)
> Log.d("PayNymDetailsActivity", "totalValueSelected:" + BigInteger.valueOf(totalValueSelected).toString())
> Log.d("PayNymDetailsActivity", "amount:" + BigInteger.valueOf(amount).toString())
> Log.d("PayNymDetailsActivity", "change:" + BigInteger.valueOf(change).toString())
> Log.d("PayNymDetailsActivity", "fee:$fee")
> if (change < 0L) {
> throw Exception(getString(R.string.bip47_cannot_compose_notif_tx))
> }
> val _outPoint: MyTransactionOutPoint = outPoint!!
> var strNotifTxMsg = getText(R.string.bip47_setup4_text1).toString() + " "
> val notifAmount = amount
> val strAmount = MonetaryUtil.getInstance().btcFormat.format((notifAmount.toDouble() + fee.toLong()) / 1e8) + " BTC "
> strNotifTxMsg += strAmount + getText(R.string.bip47_setup4_text2)
841,842c778
< scope.launch(Dispatchers.Main) {
< try {
---
> scope.launch(Dispatchers.Main) {
848,868c784,800
< scope.launch(Dispatchers.IO) {
< try {
< var tx = SendFactory.getInstance(this@PayNymDetailsActivity)
< .makeTransaction(outpoints, receivers)
< if (tx != null) {
< val input0hash = tx.getInput(0L).outpoint.hash.toString()
< val input0index = tx.getInput(0L).outpoint.index.toInt()
< if (input0hash != _outPoint.txHash.toString() || input0index != _outPoint.txOutputN) {
< throw Exception(getString(R.string.bip47_cannot_compose_notif_tx))
< }
< tx = SendFactory.getInstance(this@PayNymDetailsActivity)
< .signTransaction(tx, 0)
< val hexTx = String(Hex.encode(tx.bitcoinSerialize()))
<
< var hashTx = tx.hashAsString
< var changeIdx = 0
< for (i in 0 until tx.outputs.size) {
< if (tx.getOutput(i.toLong()).value.value == change) {
< changeIdx = i
< break
< }
---
> val job = scope.launch(Dispatchers.IO) {
> var tx = SendFactory.getInstance(this@PayNymDetailsActivity).makeTransaction(outpoints, receivers)
> if (tx != null) {
> val input0hash = tx.getInput(0L).outpoint.hash.toString()
> val input0index = tx.getInput(0L).outpoint.index.toInt()
> if (input0hash != _outPoint.txHash.toString() || input0index != _outPoint.txOutputN) {
> throw Exception(getString(R.string.bip47_cannot_compose_notif_tx))
> }
> tx = SendFactory.getInstance(this@PayNymDetailsActivity).signTransaction(tx, 0)
> val hexTx = String(Hex.encode(tx.bitcoinSerialize()))
>
> var hashTx = tx.hashAsString
> var changeIdx = 0
> for (i in 0 until tx.outputs.size) {
> if (tx.getOutput(i.toLong()).value.value == change) {
> changeIdx = i
> break
869a802
> }
871,885c804,815
< var isOK = false
< var response: String?
< try {
< val rbf = createRBFSpendFromTx(tx, this@PayNymDetailsActivity)
< response =
< PushTx.getInstance(this@PayNymDetailsActivity).samourai(hexTx, null)
< Log.d("SendActivity", "pushTx:$response")
< if (response != null) {
< val jsonObject = JSONObject(response)
< if (jsonObject.has("status")) {
< if ((jsonObject.getString("status") == "ok")) {
< isOK = true
< APIFactory.getInstance(this@PayNymDetailsActivity)
< .initWallet()
< }
---
> var isOK = false
> var response: String?
> try {
> val rbf = createRBFSpendFromTx(tx, this@PayNymDetailsActivity)
> response = PushTx.getInstance(this@PayNymDetailsActivity).samourai(hexTx, null)
> Log.d("SendActivity", "pushTx:$response")
> if (response != null) {
> val jsonObject = JSONObject(response)
> if (jsonObject.has("status")) {
> if ((jsonObject.getString("status") == "ok")) {
> isOK = true
> APIFactory.getInstance(this@PayNymDetailsActivity).initWallet()
887,888d816
< } else {
< throw Exception(getString(R.string.pushtx_returns_null))
890,891c818,822
< scope.launch(Dispatchers.Main) {
< binding.progressBar.visibility = View.INVISIBLE
---
> } else {
> throw Exception(getString(R.string.pushtx_returns_null))
> }
> scope.launch(Dispatchers.Main) {
> binding.progressBar.visibility = View.INVISIBLE
893c824
< if (isOK) {
---
> if (isOK) {
895,896c826
< UTXOUtil.getInstance()
< .add(hashTx, changeIdx, "\u2623 notif tx change\u2623")
---
> UTXOUtil.getInstance().add(hashTx, changeIdx, "\u2623 notif tx change\u2623")
898,939c828,846
< Toast.makeText(
< this@PayNymDetailsActivity,
< R.string.payment_channel_init,
< Toast.LENGTH_SHORT
< ).show()
< //
< // set outgoing index for payment code to 0
< //
< BIP47Meta.getInstance().setOutgoingIdx(pcode, 0)
< // Log.i("SendNotifTxFactory", "tx hash:" + tx.getHashAsString());
< //
< // status to NO_CFM
< //
< BIP47Meta.getInstance().setOutgoingStatus(
< pcode,
< tx.hashAsString,
< BIP47Meta.STATUS_SENT_NO_CFM
< )
<
< //updateRBFSpendForBroadcastTxAndRegister(rbf, tx, samFeeAddress, 84, this@PayNymDetailsActivity)
<
< //
< // increment change index
< //
< if (change > 0L) {
< BIP49Util.getInstance(this@PayNymDetailsActivity)
< .wallet.getAccount(0).change.incAddrIdx()
< }
< if (!BIP47Meta.getInstance().exists(pcode, false)) {
< BIP47Meta.getInstance().setLabel(
< pcode,
< BIP47Meta.getInstance().getAbbreviatedPcode(pcode)
< );
< BIP47Meta.getInstance().setFollowing(pcode, true);
< }
< savePayLoad()
< } else {
< Toast.makeText(
< this@PayNymDetailsActivity,
< R.string.tx_failed,
< Toast.LENGTH_SHORT
< ).show()
---
> Toast.makeText(this@PayNymDetailsActivity, R.string.payment_channel_init, Toast.LENGTH_SHORT).show()
> //
> // set outgoing index for payment code to 0
> //
> BIP47Meta.getInstance().setOutgoingIdx(pcode, 0)
> // Log.i("SendNotifTxFactory", "tx hash:" + tx.getHashAsString());
> //
> // status to NO_CFM
> //
> BIP47Meta.getInstance().setOutgoingStatus(pcode, tx.hashAsString, BIP47Meta.STATUS_SENT_NO_CFM)
>
> updateRBFSpendForBroadcastTxAndRegister(rbf, tx, samFeeAddress, 84, this@PayNymDetailsActivity)
>
> //
> // increment change index
> //
> if (change > 0L) {
> BIP49Util.getInstance(this@PayNymDetailsActivity)
> .wallet.getAccount(0).change.incAddrIdx()
941,942c848,850
< scope.launch(Dispatchers.Main) {
< setPayNym()
---
> if (!BIP47Meta.getInstance().exists(pcode, false)) {
> BIP47Meta.getInstance().setLabel(pcode, BIP47Meta.getInstance().getAbbreviatedPcode(pcode));
> BIP47Meta.getInstance().setRole(pcode, true);
943a852,857
> savePayLoad()
> } else {
> Toast.makeText(this@PayNymDetailsActivity, R.string.tx_failed, Toast.LENGTH_SHORT).show()
> }
> scope.launch(Dispatchers.Main) {
> setPayNym()
945,946d858
< } catch (e: Exception) {
< manageException(e)
947a860,861
> } catch (e: Exception) {
> manageException(e)
949,950c863,868
< } catch (t: Throwable) {
< manageException(t)
---
> }
> }
>
> job.invokeOnCompletion {
> if (nonNull(it)) {
> manageException(it!!)
954,955c872,879
< } catch (t: Throwable) {
< manageException(t)
---
> }.invokeOnCompletion {
> if (nonNull(it)) {
> manageException(it!!)
> }
> }
> }.invokeOnCompletion {
> if (nonNull(it)) {
> manageException(it!!)
957a882
> return
983d907
< BIP47Meta.getInstance().setName(pcode, strNymName)
1030c954
< }
---
> }
\ No newline at end of file
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/PayNymHome.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/PayNymHome.kt
81,83d80
<
< window.statusBarColor = resources.getColor(R.color.grey_accent)
<
143a141,143
> if (!PrefsUtil.getInstance(this).getValue(PrefsUtil.PAYNYM_CLAIMED, false)) {
> doClaimPayNym()
> }
182a183,190
> private fun doClaimPayNym() {
> val payNymOnBoardBottomSheet = PayNymOnBoardBottomSheet()
> payNymOnBoardBottomSheet.show(supportFragmentManager, payNymOnBoardBottomSheet.tag)
> payNymOnBoardBottomSheet.setOnClaimCallBack {
> payNymViewModel.refreshPayNym()
> }
> }
>
207d214
< /*
211d217
< */
260c266
< var url = "null"; //"https://samouraiwallet.com/support"
---
> var url = "https://samouraiwallet.com/support"
262,265c268,271
< url = "null"; // "http://72typmu5edrjmcdkzuzmv2i4zqru7rjlrcxwtod4nu6qtfsqegngzead.onion/support"
< val intent = Intent(this, ExplorerActivity::class.java)
< intent.putExtra(ExplorerActivity.SUPPORT, url)
< startActivity(intent)
---
> url = "http://72typmu5edrjmcdkzuzmv2i4zqru7rjlrcxwtod4nu6qtfsqegngzead.onion/support"
> val explorerIntent = Intent(this, ExplorerActivity::class.java)
> explorerIntent.putExtra(ExplorerActivity.SUPPORT, url)
> startActivity(explorerIntent)
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/paynym/PayNymViewModel.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/paynym/PayNymViewModel.kt
4d3
< import android.util.Log
17,18d15
< import com.samourai.wallet.util.PrefsUtil
< import com.samourai.wallet.util.func.isClaimedPayNym
19a17
> import com.samourai.wallet.util.PrefsUtil
20a19
> import kotlinx.coroutines.Deferred
27,28d25
< import kotlinx.coroutines.sync.Semaphore
< import kotlinx.coroutines.sync.withPermit
33d29
< import java.util.concurrent.atomic.AtomicInteger
69c65
< BIP47Meta.getInstance().setFollowings(backupFilePaynyms as java.util.ArrayList<String>?)
---
> BIP47Meta.getInstance().addFollowings(backupFilePaynyms as java.util.ArrayList<String>?)
77,78c73,77
< val pcode = BIP47Util.getInstance(getApplication()).paymentCode.toString()
< if (isClaimedPayNym(pcode, jsonObject)) {
---
> val nym = Gson().fromJson(jsonObject.toString(), NymResponse::class.java);
> val backupFilePaynyms = PayloadUtil.getInstance(getApplication<Application>().applicationContext).paynymsFromBackupFile
>
> var array = jsonObject.getJSONArray("codes")
> if (array.getJSONObject(0).has("claimed") && array.getJSONObject(0).getBoolean("claimed")) {
85,87d83
< val backupFilePaynyms = PayloadUtil.getInstance(getApplication<Application>().applicationContext).paynymsFromBackupFile
<
< val nym = Gson().fromJson(jsonObject.toString(), NymResponse::class.java)
91d86
< BIP47Meta.getInstance().setName(paynym.code, paynym.nymName)
101c96
< BIP47Meta.getInstance().setFollowings(followings)
---
> BIP47Meta.getInstance().addFollowings(followings)
110d104
< BIP47Meta.getInstance().setName(paynym.code, paynym.nymName)
116c110
< sortByLabel(followers);
---
> sortByLabel(followers);
137c131
< suspend fun getPayNymData() {
---
> private suspend fun getPayNymData() {
204,208c198,205
<
< try {
< if (_pcodes.contains(BIP47Util.getInstance(getApplication()).paymentCode.toString())) {
< _pcodes.remove(BIP47Util.getInstance(getApplication()).paymentCode.toString())
< BIP47Meta.getInstance().remove(BIP47Util.getInstance(getApplication()).paymentCode.toString())
---
> refreshJob = viewModelScope.launch(Dispatchers.IO) {
> try {
> if (_pcodes.contains(BIP47Util.getInstance(getApplication()).paymentCode.toString())) {
> _pcodes.remove(BIP47Util.getInstance(getApplication()).paymentCode.toString())
> BIP47Meta.getInstance().remove(BIP47Util.getInstance(getApplication()).paymentCode.toString())
> }
> } catch (afe: AddressFormatException) {
> afe.printStackTrace()
210,217c207,208
< } catch (afe: AddressFormatException) {
< afe.printStackTrace()
< }
<
< refreshJob = viewModelScope.launch(Dispatchers.Main) {
<
< var progress = AtomicInteger(0)
<
---
> var progress = 0;
> val jobs = arrayListOf<Deferred<Unit>>()
219,250c210,217
< refreshTaskProgress.postValue(Pair(progress.get(), _pcodes.size))
<
< viewModelScope.launch(Dispatchers.IO) {
< BIP47Util.getInstance(getApplication()).fetchBotImage().subscribe()
< }
<
< withContext(Dispatchers.IO) {
< val semaphore = Semaphore(6)
< val tasks = _pcodes.map { pcode ->
< async(Dispatchers.IO) {
< semaphore.withPermit {
< try {
< apiService.syncPcode(pcode)
< val progress = progress.incrementAndGet()
< if (!silentSync) {
< if(progress < _pcodes.size) {
< refreshTaskProgress.postValue(Pair(progress, _pcodes.size))
< }
< }
< true
< } catch (te : Throwable) {
< Log.e(TAG, "issue on syncPcode " + pcode, te)
< }
< }
< }
< }
< tasks.awaitAll()
< async(Dispatchers.IO) {
< try {
< apiService.retrievePayNymConnections()
< val progress = progress.incrementAndGet()
< if (!silentSync) {
---
> refreshTaskProgress.postValue(Pair(0, _pcodes.size))
> _pcodes.forEachIndexed { _, pcode ->
> val job = async(Dispatchers.IO) { apiService.syncPcode(pcode) }
> jobs.add(job)
> job.invokeOnCompletion {
> if (it == null) {
> progress++
> if (!silentSync)
252,254c219,220
< }
< } catch (te : Throwable) {
< Log.e(TAG, "issue on retrievePayNymConnections", te)
---
> } else {
> it.printStackTrace()
256,257c222
< true
< }.await()
---
> }
258a224,226
> BIP47Util.getInstance(getApplication()).fetchBotImage()
> .subscribe()
> jobs.awaitAll()
266,267c234,235
< suspend fun doFollow(pcode: String) {
< val job = viewModelScope.launch {
---
> fun doFollow(pcode: String) {
> viewModelScope.launch {
284,285c252
< }
< job.invokeOnCompletion {
---
> }.invokeOnCompletion {
293d259
< job.join()
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/pin/PinEntryActivity.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/pin/PinEntryActivity.java
3,5d2
< import static com.samourai.wallet.payload.ExternalBackupManager.askPermission;
< import static com.samourai.wallet.payload.ExternalBackupManager.hasPermissions;
<
17d13
< import com.samourai.wallet.util.PrefsUtil;
37,42d32
<
< if (! PrefsUtil.getInstance(this).getValue(PrefsUtil.WALLET_SCAN_COMPLETE, false)) {
< if (PrefsUtil.getInstance(this).getValue(PrefsUtil.AUTO_BACKUP, true)) {
< if (!hasPermissions()) askPermission(this);
< }
< }
48c38
< AppUtil.getInstance(this).restartAppFromActivity(getIntent().getExtras(), this);
---
> AppUtil.getInstance(this).restartApp(getIntent().getExtras());
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/pin/PinEntryManager.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/pin/PinEntryManager.java
15d14
< import android.util.Log;
41a41,42
> import com.samourai.wallet.util.func.AddressFactory;
> import com.samourai.wallet.util.tech.AppUtil;
45,48d45
< import com.samourai.wallet.util.func.AddressFactory;
< import com.samourai.wallet.util.tech.AppUtil;
< import com.samourai.wallet.util.tech.SimpleCallback;
< import com.samourai.wallet.util.tech.SimpleTaskRunner;
52d48
< import org.apache.commons.lang3.StringUtils;
68d63
< private final static String TAG = "PinEntryManager";
154,206c149
< final View theView = getView();
<
< SimpleTaskRunner.create().executeAsync(
< true,
< () -> {
< if (attemptToLog && PrefsUtil.getInstance(activity).getValue(PrefsUtil.ATTEMPTS, 0) > 0) {
< failures = PrefsUtil.getInstance(activity).getValue(PrefsUtil.ATTEMPTS, 0);
< }
< return null;
< }, new SimpleCallback<Void>() {
< @Override
< public void onComplete(Void result) {
< userInput = new StringBuilder();
< pinEntryView = theView.findViewById(R.id.pinentry_view);
< walletStatusTextView = theView.findViewById(R.id.pin_entry_wallet_status);
< restoreLayout = theView.findViewById(R.id.pin_entry_restore);
< MaterialButton restoreBtn = theView.findViewById(R.id.pin_entry_restore_btn);
< pinEntryMaskLayout = theView.findViewById(R.id.pin_entry_mask_layout);
< progressBar = theView.findViewById(R.id.progress_pin_entry);
< activity.getWindow().setStatusBarColor(ContextCompat.getColor(activity, R.color.window));
< activity.getWindow().setNavigationBarColor(ContextCompat.getColor(activity, R.color.window));
< restoreLayout.setVisibility(View.GONE);
< pinEntryView.setEntryListener((key, view) -> {
< if (userInput.length() <= (AccessFactory.MAX_PIN_LENGTH - 1)) {
< userInput = userInput.append(key);
< if (userInput.length() >= AccessFactory.MIN_PIN_LENGTH) {
< pinEntryView.showCheckButton();
< } else {
< pinEntryView.hideCheckButton();
< }
< setPinMaskView();
< }
< });
< restoreBtn.setOnClickListener(v -> doBackupRestore());
< pinEntryView.setClearListener(clearType -> {
< if (clearType == PinEntryView.KeyClearTypes.CLEAR) {
< if (userInput.length() != 0)
< userInput = new StringBuilder(userInput.substring(0, (userInput.length() - 1)));
< if (userInput.length() >= AccessFactory.MIN_PIN_LENGTH) {
< pinEntryView.showCheckButton();
< } else {
< pinEntryView.hideCheckButton();
< }
< } else {
< strPassphrase = "";
< userInput = new StringBuilder();
< pinEntryMaskLayout.removeAllViews();
< pinEntryView.hideCheckButton();
< }
< setPinMaskView();
< });
<
< boolean scramble = PrefsUtil.getInstance(activity).getValue(PrefsUtil.SCRAMBLE_PIN, false);
---
> final View viewBuilt = getView();
208,210c151,167
< strUri = PrefsUtil.getInstance(activity).getValue("SCHEMED_URI", "");
< if (strUri.length() > 0) {
< PrefsUtil.getInstance(activity).setValue("SCHEMED_URI", "");
---
> if (attemptToLog && PrefsUtil.getInstance(activity).getValue(PrefsUtil.ATTEMPTS, 0) > 0) {
> failures = PrefsUtil.getInstance(activity).getValue(PrefsUtil.ATTEMPTS, 0);
> }
> userInput = new StringBuilder();
> pinEntryView = viewBuilt.findViewById(R.id.pinentry_view);
> walletStatusTextView = viewBuilt.findViewById(R.id.pin_entry_wallet_status);
> restoreLayout = viewBuilt.findViewById(R.id.pin_entry_restore);
> MaterialButton restoreBtn = viewBuilt.findViewById(R.id.pin_entry_restore_btn);
> pinEntryMaskLayout = viewBuilt.findViewById(R.id.pin_entry_mask_layout);
> progressBar = viewBuilt.findViewById(R.id.progress_pin_entry);
> activity.getWindow().setStatusBarColor(ContextCompat.getColor(activity, R.color.window));
> restoreLayout.setVisibility(View.GONE);
> pinEntryView.setEntryListener((key, view) -> {
> if (userInput.length() <= (AccessFactory.MAX_PIN_LENGTH - 1)) {
> userInput = userInput.append(key);
> if (userInput.length() >= AccessFactory.MIN_PIN_LENGTH) {
> pinEntryView.showCheckButton();
212c169
< strUri = null;
---
> pinEntryView.hideCheckButton();
214,215c171,182
< if (scramble) {
< pinEntryView.setScramble(true);
---
> setPinMaskView();
> }
> });
> restoreBtn.setOnClickListener(v -> doBackupRestore());
> pinEntryView.setClearListener(clearType -> {
> if (clearType == PinEntryView.KeyClearTypes.CLEAR) {
> if (userInput.length() != 0)
> userInput = new StringBuilder(userInput.substring(0, (userInput.length() - 1)));
> if (userInput.length() >= AccessFactory.MIN_PIN_LENGTH) {
> pinEntryView.showCheckButton();
> } else {
> pinEntryView.hideCheckButton();
216a184,191
> } else {
> strPassphrase = "";
> userInput = new StringBuilder();
> pinEntryMaskLayout.removeAllViews();
> pinEntryView.hideCheckButton();
> }
> setPinMaskView();
> });
218c193
< Bundle extras = activity.getIntent().getExtras();
---
> boolean scramble = PrefsUtil.getInstance(activity).getValue(PrefsUtil.SCRAMBLE_PIN, false);
220,239c195,203
< if (extras != null && extras.containsKey("create") && extras.getBoolean("create")) {
< scramble = false;
< create = true;
< confirm = false;
< strSeed = extras.getString("seed");
< strPassphrase = extras.getString("passphrase");
< Toast.makeText(activity, R.string.pin_5_8, Toast.LENGTH_LONG).show();
< } else if (extras != null && extras.containsKey("confirm") && extras.getBoolean("confirm")) {
< scramble = false;
< create = false;
< confirm = true;
< strConfirm = extras.getString("first");
< strSeed = extras.getString("seed");
< strPassphrase = extras.getString("passphrase");
< Toast.makeText(activity, R.string.pin_5_8_confirm, Toast.LENGTH_LONG).show();
< } else {
< if (isLocked()) {
< lockWallet();
< }
< }
---
> strUri = PrefsUtil.getInstance(activity).getValue("SCHEMED_URI", "");
> if (strUri.length() > 0) {
> PrefsUtil.getInstance(activity).setValue("SCHEMED_URI", "");
> } else {
> strUri = null;
> }
> if (scramble) {
> pinEntryView.setScramble(true);
> }
241,243c205
< if (strSeed != null && strSeed.length() < 1) {
< strSeed = null;
< }
---
> Bundle extras = activity.getIntent().getExtras();
245,251c207,226
< if (strPassphrase == null) {
< strPassphrase = "";
< }
< if (!PrefsUtil.getInstance(activity).getValue(PrefsUtil.HAPTIC_PIN, true)) {
< pinEntryView.disableHapticFeedBack();
< }
< pinEntryView.setConfirmClickListener(view -> {
---
> if (extras != null && extras.containsKey("create") && extras.getBoolean("create")) {
> scramble = false;
> create = true;
> confirm = false;
> strSeed = extras.getString("seed");
> strPassphrase = extras.getString("passphrase");
> Toast.makeText(activity, R.string.pin_5_8, Toast.LENGTH_LONG).show();
> } else if (extras != null && extras.containsKey("confirm") && extras.getBoolean("confirm")) {
> scramble = false;
> create = false;
> confirm = true;
> strConfirm = extras.getString("first");
> strSeed = extras.getString("seed");
> strPassphrase = extras.getString("passphrase");
> Toast.makeText(activity, R.string.pin_5_8_confirm, Toast.LENGTH_LONG).show();
> } else {
> if (isLocked()) {
> lockWallet();
> }
> }
253,262c228,230
< if (create && strPassphrase.length() >= AccessFactory.MIN_PIN_LENGTH && userInput.toString().length() <= AccessFactory.MAX_PIN_LENGTH) {
< Intent intent = new Intent(activity, PinEntryActivity.class);
< intent.putExtra("confirm", true);
< intent.putExtra("create", false);
< intent.putExtra("first", userInput.toString());
< intent.putExtra("seed", strSeed);
< intent.putExtra("passphrase", strPassphrase);
< activity.startActivity(intent);
< activity.finish();
< } else if (confirm && strPassphrase.length() >= AccessFactory.MIN_PIN_LENGTH && userInput.toString().length() <= AccessFactory.MAX_PIN_LENGTH) {
---
> if (strSeed != null && strSeed.length() < 1) {
> strSeed = null;
> }
264c232,238
< if (userInput.toString().equals(strConfirm)) {
---
> if (strPassphrase == null) {
> strPassphrase = "";
> }
> if (!PrefsUtil.getInstance(activity).getValue(PrefsUtil.HAPTIC_PIN, true)) {
> pinEntryView.disableHapticFeedBack();
> }
> pinEntryView.setConfirmClickListener(view -> {
266c240,249
< progressBar.setVisibility(View.VISIBLE);
---
> if (create && strPassphrase.length() >= AccessFactory.MIN_PIN_LENGTH && userInput.toString().length() <= AccessFactory.MAX_PIN_LENGTH) {
> Intent intent = new Intent(activity, PinEntryActivity.class);
> intent.putExtra("confirm", true);
> intent.putExtra("create", false);
> intent.putExtra("first", userInput.toString());
> intent.putExtra("seed", strSeed);
> intent.putExtra("passphrase", strPassphrase);
> activity.startActivity(intent);
> activity.finish();
> } else if (confirm && strPassphrase.length() >= AccessFactory.MIN_PIN_LENGTH && userInput.toString().length() <= AccessFactory.MAX_PIN_LENGTH) {
268c251
< initThread(strSeed == null, userInput.toString(), strPassphrase, strSeed == null ? null : strSeed);
---
> if (userInput.toString().equals(strConfirm)) {
270,277c253
< } else {
< Intent intent = new Intent(activity, PinEntryActivity.class);
< intent.putExtra("create", true);
< intent.putExtra("seed", strSeed);
< intent.putExtra("passphrase", strPassphrase);
< activity.startActivity(intent);
< activity.finish();
< }
---
> progressBar.setVisibility(View.VISIBLE);
279,283c255,264
< } else {
< validateThread(userInput.toString(), strUri);
< }
< });
< }
---
> initThread(strSeed == null, userInput.toString(), strPassphrase, strSeed == null ? null : strSeed);
>
> } else {
> Intent intent = new Intent(activity, PinEntryActivity.class);
> intent.putExtra("create", true);
> intent.putExtra("seed", strSeed);
> intent.putExtra("passphrase", strPassphrase);
> activity.startActivity(intent);
> activity.finish();
> }
285,287c266,267
< @Override
< public void onException(Throwable t) {
< Log.e(TAG, "issue on install view", t);
---
> } else {
> validateThread(userInput.toString(), strUri);
350c330
< AppUtil.getInstance(activity).restartAppFromActivity(activity.getIntent().getExtras(), activity);
---
> AppUtil.getInstance(activity).restartApp(activity.getIntent().getExtras());
362c342
< AppUtil.getInstance(activity).restartAppFromActivity(activity.getIntent().getExtras(), activity);
---
> AppUtil.getInstance(activity).restartApp(activity.getIntent().getExtras());
415c395
< AppUtil.getInstance(activity).restartAppFromActivity(activity.getIntent().getExtras(), activity);
---
> AppUtil.getInstance(activity).restartApp(activity.getIntent().getExtras());
466,473c446
< SimpleTaskRunner.create().executeAsync(
< true,
< () -> {
<
< String guid = AccessFactory.getInstance(activity).createGUID();
< String hash = AccessFactory.getInstance(activity).getHash(guid, new CharSequenceX(pin), AESUtil.DefaultPBKDF2Iterations);
< PrefsUtil.getInstance(activity).setValue(PrefsUtil.ACCESS_HASH, hash);
< PrefsUtil.getInstance(activity).setValue(PrefsUtil.ACCESS_HASH2, hash);
---
> new Thread(() -> {
475c448
< if (create) {
---
> Looper.prepare();
477,485c450,465
< try {
< HD_WalletFactory.getInstance(activity).newWallet(12, passphrase);
< } catch (IOException ioe) {
< ioe.printStackTrace();
< } catch (MnemonicException.MnemonicLengthException mle) {
< mle.printStackTrace();
< } finally {
< ;
< }
---
> String guid = AccessFactory.getInstance(activity).createGUID();
> String hash = AccessFactory.getInstance(activity).getHash(guid, new CharSequenceX(pin), AESUtil.DefaultPBKDF2Iterations);
> PrefsUtil.getInstance(activity).setValue(PrefsUtil.ACCESS_HASH, hash);
> PrefsUtil.getInstance(activity).setValue(PrefsUtil.ACCESS_HASH2, hash);
>
> if (create) {
>
> try {
> HD_WalletFactory.getInstance(activity).newWallet(12, passphrase);
> } catch (IOException ioe) {
> ioe.printStackTrace();
> } catch (MnemonicException.MnemonicLengthException mle) {
> mle.printStackTrace();
> } finally {
> ;
> }
487,489c467,469
< } else if (seed == null) {
< ;
< } else {
---
> } else if (seed == null) {
> ;
> } else {
491,507c471,487
< try {
< HD_WalletFactory.getInstance(activity).restoreWallet(seed, passphrase);
< } catch (IOException ioe) {
< ioe.printStackTrace();
< } catch (DecoderException de) {
< de.printStackTrace();
< } catch (AddressFormatException afe) {
< afe.printStackTrace();
< } catch (MnemonicException.MnemonicLengthException mle) {
< mle.printStackTrace();
< } catch (MnemonicException.MnemonicChecksumException mce) {
< mce.printStackTrace();
< } catch (MnemonicException.MnemonicWordException mwe) {
< mwe.printStackTrace();
< } finally {
< ;
< }
---
> try {
> HD_WalletFactory.getInstance(activity).restoreWallet(seed, passphrase);
> } catch (IOException ioe) {
> ioe.printStackTrace();
> } catch (DecoderException de) {
> de.printStackTrace();
> } catch (AddressFormatException afe) {
> afe.printStackTrace();
> } catch (MnemonicException.MnemonicLengthException mle) {
> mle.printStackTrace();
> } catch (MnemonicException.MnemonicChecksumException mce) {
> mce.printStackTrace();
> } catch (MnemonicException.MnemonicWordException mwe) {
> mwe.printStackTrace();
> } finally {
> ;
> }
509c489,491
< }
---
> }
>
> PrefsUtil.getInstance(activity).setValue(PrefsUtil.SCRAMBLE_PIN, true);
511c493
< PrefsUtil.getInstance(activity).setValue(PrefsUtil.SCRAMBLE_PIN, true);
---
> try {
513c495
< String msg;
---
> String msg = null;
515c497,507
< if (HD_WalletFactory.getInstance(activity).get() != null) {
---
> if (HD_WalletFactory.getInstance(activity).get() != null) {
>
> if (create) {
> msg = activity.getString(R.string.wallet_created_ok);
> } else {
> msg = activity.getString(R.string.wallet_restored_ok);
> }
>
> try {
> AccessFactory.getInstance(activity).setPIN(pin);
> PayloadUtil.getInstance(activity).saveWalletToJSON(new CharSequenceX(AccessFactory.getInstance(activity).getGUID() + pin));
518c510,511
< msg = activity.getString(R.string.wallet_created_ok);
---
> PrefsUtil.getInstance(activity).setValue(PrefsUtil.WALLET_ORIGIN, "new");
> PrefsUtil.getInstance(activity).setValue(PrefsUtil.FIRST_RUN, true);
520c513,514
< msg = activity.getString(R.string.wallet_restored_ok);
---
> PrefsUtil.getInstance(activity).setValue(PrefsUtil.WALLET_ORIGIN, "restored");
> PrefsUtil.getInstance(activity).setValue(PrefsUtil.FIRST_RUN, true);
523,537c517,519
< try {
< AccessFactory.getInstance(activity).setPIN(pin);
< PayloadUtil.getInstance(activity).saveWalletToJSON(new CharSequenceX(AccessFactory.getInstance(activity).getGUID() + pin));
<
< if (create) {
< PrefsUtil.getInstance(activity).setValue(PrefsUtil.WALLET_ORIGIN, "new");
< PrefsUtil.getInstance(activity).setValue(PrefsUtil.WALLET_SCAN_COMPLETE, false);
< } else {
< PrefsUtil.getInstance(activity).setValue(PrefsUtil.WALLET_ORIGIN, "restored");
< PrefsUtil.getInstance(activity).setValue(PrefsUtil.WALLET_SCAN_COMPLETE, false);
< }
<
< } catch (JSONException | IOException | DecryptionException je) {
< je.printStackTrace();
< }
---
> } catch (JSONException | IOException | DecryptionException je) {
> je.printStackTrace();
> }
539,542c521,524
< for (int i = 0; i < 2; i++) {
< AddressFactory.getInstance().account2xpub().put(i, HD_WalletFactory.getInstance(activity).get().getAccount(i).xpubstr());
< AddressFactory.getInstance().xpub2account().put(HD_WalletFactory.getInstance(activity).get().getAccount(i).xpubstr(), i);
< }
---
> for (int i = 0; i < 2; i++) {
> AddressFactory.getInstance().account2xpub().put(i, HD_WalletFactory.getInstance(activity).get().getAccount(i).xpubstr());
> AddressFactory.getInstance().xpub2account().put(HD_WalletFactory.getInstance(activity).get().getAccount(i).xpubstr(), i);
> }
544,547c526,529
< //
< // backup wallet for alpha
< //
< if (create) {
---
> //
> // backup wallet for alpha
> //
> if (create) {
549,562c531
< SimpleTaskRunner.create().executeAsync(
< true,
< () -> HD_WalletFactory.getInstance(activity).get().getMnemonic(),
< new SimpleCallback<String>() {
< @Override
< public void onComplete(String seed1) {
< final Intent intent = new Intent(activity, RecoveryWordsActivity.class);
< intent.putExtra(RecoveryWordsActivity.WORD_LIST, seed1);
< intent.putExtra(RecoveryWordsActivity.PASSPHRASE, passphrase);
< activity.startActivity(intent);
< activity.finish();
< }
< }
< );
---
> String seed1 = HD_WalletFactory.getInstance(activity).get().getMnemonic();
564,580c533,537
< } else {
< SimpleTaskRunner.create().executeAsync(
< true,
< () -> {
< AccessFactory.getInstance(activity).setIsLoggedIn(true);
< TimeOutUtil.getInstance().updatePin();
< return null;
< },
< new SimpleCallback<Void>() {
< @Override
< public void onComplete(Void result) {
< AppUtil.getInstance(activity).restartAppFromActivity(activity.getIntent().getExtras(), activity);
< activity.finish();
< }
< }
< );
< }
---
> Intent intent = new Intent(activity, RecoveryWordsActivity.class);
> intent.putExtra(RecoveryWordsActivity.WORD_LIST, seed1);
> intent.putExtra(RecoveryWordsActivity.PASSPHRASE, passphrase);
> activity.startActivity(intent);
> activity.finish();
583,596c540,543
< if (create) {
< msg = activity.getString(R.string.wallet_created_ko);
< } else {
< msg = activity.getString(R.string.wallet_restored_ko);
< }
< }
<
< return msg;
< },
< new SimpleCallback<String>() {
< @Override
< public void onComplete(String msg) {
< Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show();
< progressBar.setVisibility(View.INVISIBLE);
---
> AccessFactory.getInstance(activity).setIsLoggedIn(true);
> TimeOutUtil.getInstance().updatePin();
> AppUtil.getInstance(activity).restartApp(activity.getIntent().getExtras());
> activity.finish();
599,601c546,550
< @Override
< public void onException(Throwable t) {
< Log.e(TAG, "issue on initThread()", t);
---
> } else {
> if (create) {
> msg = activity.getString(R.string.wallet_created_ko);
> } else {
> msg = activity.getString(R.string.wallet_restored_ko);
604c553,565
< );
---
>
> Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show();
>
> } catch (final Exception e) {
> e.printStackTrace();
> }
>
> progressBar.setVisibility(View.INVISIBLE);
>
> Looper.loop();
>
> }).start();
>
611,612c572,573
< SimpleTaskRunner.create().executeAsyncAndShutdown(
< () -> {
---
> new Thread(() -> {
> Looper.prepare();
614,622c575,583
< if (pin.length() < AccessFactory.MIN_PIN_LENGTH || pin.length() > AccessFactory.MAX_PIN_LENGTH) {
< activity.runOnUiThread(() -> {
< progressBar.setVisibility(View.INVISIBLE);
< pinEntryView.resetPinLen();
< Toast.makeText(activity, R.string.pin_error, Toast.LENGTH_SHORT).show();
< AppUtil.getInstance(activity).restartAppFromActivity(activity.getIntent().getExtras(), activity);
< activity.finish();
< });
< }
---
> if (pin.length() < AccessFactory.MIN_PIN_LENGTH || pin.length() > AccessFactory.MAX_PIN_LENGTH) {
> activity.runOnUiThread(() -> {
> progressBar.setVisibility(View.INVISIBLE);
> pinEntryView.resetPinLen();
> });
> Toast.makeText(activity, R.string.pin_error, Toast.LENGTH_SHORT).show();
> AppUtil.getInstance(activity).restartApp(activity.getIntent().getExtras());
> activity.finish();
> }
624,633c585,594
< String randomKey = AccessFactory.getInstance(activity).getGUID();
< if (StringUtils.isEmpty(randomKey)) {
< activity.runOnUiThread(() -> {
< progressBar.setVisibility(View.INVISIBLE);
< pinEntryView.resetPinLen();
< Toast.makeText(activity, R.string.random_key_error, Toast.LENGTH_SHORT).show();
< AppUtil.getInstance(activity).restartAppFromActivity(activity.getIntent().getExtras(), activity);
< activity.finish();
< });
< }
---
> String randomKey = AccessFactory.getInstance(activity).getGUID();
> if (randomKey.length() < 1) {
> activity.runOnUiThread(() -> {
> progressBar.setVisibility(View.INVISIBLE);
> pinEntryView.resetPinLen();
> });
> Toast.makeText(activity, R.string.random_key_error, Toast.LENGTH_SHORT).show();
> AppUtil.getInstance(activity).restartApp(activity.getIntent().getExtras());
> activity.finish();
> }
635,636c596,597
< String hash = PrefsUtil.getInstance(activity).getValue(PrefsUtil.ACCESS_HASH, "");
< if (AccessFactory.getInstance(activity).validateHash(hash, randomKey, new CharSequenceX(pin), AESUtil.DefaultPBKDF2Iterations)) {
---
> String hash = PrefsUtil.getInstance(activity).getValue(PrefsUtil.ACCESS_HASH, "");
> if (AccessFactory.getInstance(activity).validateHash(hash, randomKey, new CharSequenceX(pin), AESUtil.DefaultPBKDF2Iterations)) {
638c599
< AccessFactory.getInstance(activity).setPIN(pin);
---
> AccessFactory.getInstance(activity).setPIN(pin);
640c601
< try {
---
> try {
642,656c603,604
< if (attemptToLog) {
< HD_Wallet hdw = PayloadUtil.getInstance(activity)
< .restoreWalletfromJSON(new CharSequenceX(AccessFactory.getInstance(activity).getGUID() + pin));
<
< if (isNull(hdw)) {
<
< activity.runOnUiThread(() -> {
< incFailures();
< PrefsUtil.getInstance(activity).setValue(PrefsUtil.ATTEMPTS, failures);
< pinEntryMaskLayout.removeAllViews();
< pinEntryView.hideCheckButton();
< pinEntryView.resetPinLen();
< setPinMaskView();
< managePinFailureCount();
< });
---
> if (attemptToLog) {
> HD_Wallet hdw = PayloadUtil.getInstance(activity).restoreWalletfromJSON(new CharSequenceX(AccessFactory.getInstance(activity).getGUID() + pin));
658,661c606
< } else {
< PrefsUtil.getInstance(activity).setValue(PrefsUtil.ATTEMPTS, 0);
< }
< }
---
> if (isNull(hdw)) {
664c609,615
< fireOnSuccessMessage();
---
> incFailures();
> PrefsUtil.getInstance(activity).setValue(PrefsUtil.ATTEMPTS, failures);
> pinEntryMaskLayout.removeAllViews();
> pinEntryView.hideCheckButton();
> pinEntryView.resetPinLen();
> setPinMaskView();
> managePinFailureCount();
667,672c618,619
< } catch (final Exception e) {
< e.printStackTrace();
< } finally {
< activity.runOnUiThread(() -> {
< progressBar.setVisibility(View.INVISIBLE);
< });
---
> } else {
> PrefsUtil.getInstance(activity).setValue(PrefsUtil.ATTEMPTS, 0);
674,686d620
<
< } else {
< activity.runOnUiThread(() -> {
< progressBar.setVisibility(View.INVISIBLE);
< incFailures();
< PrefsUtil.getInstance(activity).setValue(PrefsUtil.ATTEMPTS, failures);
< userInput = new StringBuilder();
< pinEntryMaskLayout.removeAllViews();
< pinEntryView.hideCheckButton();
< pinEntryView.resetPinLen();
< managePinFailureCount();
< });
<
688a623,627
> fireOnSuccessMessage();
>
> } catch (final Exception e) {
> e.printStackTrace();
> } finally {
691d629
<
694c632,653
< );
---
>
> } else {
> activity.runOnUiThread(() -> {
> progressBar.setVisibility(View.INVISIBLE);
> incFailures();
> PrefsUtil.getInstance(activity).setValue(PrefsUtil.ATTEMPTS, failures);
> userInput = new StringBuilder();
> pinEntryMaskLayout.removeAllViews();
> pinEntryView.hideCheckButton();
> pinEntryView.resetPinLen();
> managePinFailureCount();
> });
>
> }
>
> activity.runOnUiThread(() -> {
> progressBar.setVisibility(View.INVISIBLE);
>
> });
>
> }).start();
>
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/ReceiveActivity.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/ReceiveActivity.java
5,6d4
< import android.content.ClipData;
< import android.content.ClipboardManager;
16d13
< import android.os.Build;
22d18
< import android.util.Log;
38,39d33
< import com.google.common.collect.ImmutableListMultimap;
< import com.google.common.collect.ListMultimap;
50d43
< import com.samourai.wallet.util.func.EnumAddressType;
55,56d47
< import com.samourai.wallet.util.tech.SimpleCallback;
< import com.samourai.wallet.util.tech.SimpleTaskRunner;
58d48
< import org.apache.commons.lang3.StringUtils;
74d63
< import java.util.concurrent.Callable;
87,88d75
<
< private static final String TAG = "ReceiveActivity";
159d145
< getWindow().setStatusBarColor(getResources().getColor(R.color.grey_accent));
184a171,172
> useSegwit = PrefsUtil.getInstance(ReceiveActivity.this).getValue(PrefsUtil.USE_SEGWIT, true);
>
194,219c182,221
< SimpleTaskRunner.create().executeAsync(
< true,
< new Callable<Void>() {
< @Override
< public Void call() throws Exception {
<
< Pair<Integer, String> pair84 = AddressFactory.getInstance(ReceiveActivity.this).getAddress(WALLET_INDEX.BIP84_RECEIVE);
< addr84 = pair84.getRight();
< idx84 = pair84.getLeft();
< Pair<Integer, String> pair49 = AddressFactory.getInstance(ReceiveActivity.this).getAddress(WALLET_INDEX.BIP49_RECEIVE);
< addr49 = pair49.getRight();
< idx49 = pair49.getLeft();
< Pair<Integer, String> pair44 = AddressFactory.getInstance(ReceiveActivity.this).getAddress(WALLET_INDEX.BIP44_RECEIVE);
< addr44 = pair44.getRight();
< idx44 = pair44.getLeft();
<
< useSegwit = PrefsUtil.getInstance(ReceiveActivity.this).getValue(PrefsUtil.USE_SEGWIT, true);
<
< if (useSegwit && isBIP84Selected()) {
< addr = addr84;
< idx = idx84;
< AddressFactory.getInstance(ReceiveActivity.this).increment(WALLET_INDEX.BIP84_RECEIVE);
< inc84 = true;
< } else if (useSegwit && !isBIP84Selected()) {
< addr = addr49;
< idx = idx49;
---
> Pair<Integer, String> pair84 = AddressFactory.getInstance(ReceiveActivity.this).getAddress(WALLET_INDEX.BIP84_RECEIVE);
> addr84 = pair84.getRight();
> idx84 = pair84.getLeft();
> Pair<Integer, String> pair49 = AddressFactory.getInstance(ReceiveActivity.this).getAddress(WALLET_INDEX.BIP49_RECEIVE);
> addr49 = pair49.getRight();
> idx49 = pair49.getLeft();
> Pair<Integer, String> pair44 = AddressFactory.getInstance(ReceiveActivity.this).getAddress(WALLET_INDEX.BIP44_RECEIVE);
> addr44 = pair44.getRight();
> idx44 = pair44.getLeft();
>
> if (!useSegwit) {
> addressTypesSpinner.setSelection(2);
> }
>
> if (useSegwit && isBIP84Selected()) {
> addr = addr84;
> idx = idx84;
> AddressFactory.getInstance(ReceiveActivity.this).increment(WALLET_INDEX.BIP84_RECEIVE);
> inc84 = true;
> }
> else if (useSegwit && !isBIP84Selected()) {
> addr = addr49;
> idx = idx49;
> AddressFactory.getInstance(ReceiveActivity.this).increment(WALLET_INDEX.BIP49_RECEIVE);
> inc49 = true;
> }
> else {
> addr = addr44;
> idx = idx44;
> AddressFactory.getInstance(ReceiveActivity.this).increment(WALLET_INDEX.BIP44_RECEIVE);
> inc44 = true;
> }
> addressTypesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
> @Override
> public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
> switch (position) {
> case 1: {
> addr = addr49;
> idx = idx49;
> if(!inc49) {
222,224c224,230
< } else {
< addr = addr44;
< idx = idx44;
---
> }
> break;
> }
> case 2: {
> addr = addr44;
> idx = idx44;
> if(!inc44) {
228c234
< return null;
---
> break;
230,235c236,241
< },
< new SimpleCallback<Void>() {
< @Override
< public void onComplete(Void result) {
< if (!useSegwit) {
< addressTypesSpinner.setSelection(2);
---
> default: {
> addr = addr84;
> idx = idx84;
> if(!inc84) {
> AddressFactory.getInstance(ReceiveActivity.this).increment(WALLET_INDEX.BIP84_RECEIVE);
> inc84 = true;
237d242
< displayQRCode();
239,291c244,245
<
< @Override
< public void onException(Throwable t) {
< Log.e(TAG, "issue on computing addresses");
< }
< });
<
< addressTypesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
< @Override
< public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
< SimpleTaskRunner.create().executeAsync(
< true,
< new Callable<Void>() {
< @Override
< public Void call() throws Exception {
< switch (position) {
< case 1: {
< addr = addr49;
< idx = idx49;
< if(!inc49) {
< AddressFactory.getInstance(ReceiveActivity.this).increment(WALLET_INDEX.BIP49_RECEIVE);
< inc49 = true;
< }
< break;
< }
< case 2: {
< addr = addr44;
< idx = idx44;
< if(!inc44) {
< AddressFactory.getInstance(ReceiveActivity.this).increment(WALLET_INDEX.BIP44_RECEIVE);
< inc44 = true;
< }
< break;
< }
< default: {
< addr = addr84;
< idx = idx84;
< if(!inc84) {
< AddressFactory.getInstance(ReceiveActivity.this).increment(WALLET_INDEX.BIP84_RECEIVE);
< inc84 = true;
< }
< }
< }
< return null;
< }
< },
< new SimpleCallback<Void>() {
< @Override
< public void onComplete(Void result) {
< displayQRCode();
< }
< }
< );
---
> }
> displayQRCode();
311,329c265,269
< SimpleTaskRunner.create().executeAsync(
< true,
< new Callable<Void>() {
< @Override
< public Void call() throws Exception {
< final ClipboardManager clipboard = (ClipboardManager) ReceiveActivity.this.getSystemService(Context.CLIPBOARD_SERVICE);
< ClipData clip = null;
< clip = ClipData.newPlainText("Receive address", addr);
< clipboard.setPrimaryClip(clip);
< return null;
< }
< },
< new SimpleCallback<Void>() {
< @Override
< public void onComplete(Void result) {
< Toast.makeText(ReceiveActivity.this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show();
< }
< }
< );
---
> android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ReceiveActivity.this.getSystemService(android.content.Context.CLIPBOARD_SERVICE);
> android.content.ClipData clip = null;
> clip = android.content.ClipData.newPlainText("Receive address", addr);
> clipboard.setPrimaryClip(clip);
> Toast.makeText(ReceiveActivity.this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show();
380a321,322
>
> displayQRCode();
539,598c481,528
< SimpleTaskRunner.create().executeAsync(
< true,
< new Callable<File>() {
< @Override
< public File call() throws Exception {
< final String strFileName = AppUtil.getInstance(ReceiveActivity.this).getReceiveQRFilename();
< File file = new File(strFileName);
< if (!file.exists()) {
< try {
< file.createNewFile();
< } catch (Exception e) {
< Toast.makeText(ReceiveActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
< return null;
< }
< }
< file.setReadable(true, false);
<
< final ClipboardManager clipboard = (ClipboardManager) ReceiveActivity.this.getSystemService(Context.CLIPBOARD_SERVICE);
< clipboard.setPrimaryClip(ClipData.newPlainText("Receive address", addr));
<
< try (FileOutputStream fos = new FileOutputStream(file)) {
< Bitmap bitmap = ((BitmapDrawable) ivQR.getDrawable()).getBitmap();
< bitmap.compress(Bitmap.CompressFormat.PNG, 0, fos);
< return file;
< } catch (FileNotFoundException fnfe) {
< ;
< }
<
< return null;
< }
< },
< new SimpleCallback<File>() {
< @Override
< public void onComplete(File file) {
<
< final Intent intent = new Intent();
< intent.setAction(Intent.ACTION_SEND);
< Uri uri;
< if (Build.VERSION.SDK_INT >= 24) {
< uri = FileProvider.getUriForFile(
< ReceiveActivity.this,
< getApplicationContext()
< .getPackageName() + ".provider", file);
< } else {
< uri = Uri.fromFile(file);
< }
< intent.setDataAndType(uri, "image/png");
< intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
< final Intent chooser = Intent.createChooser(
< intent,
< ReceiveActivity.this.getText(R.string.send_payment_code));
< startActivity(chooser);
< }
<
< @Override
< public void onException(Throwable t) {
< SimpleCallback.super.onException(t);
< }
< }
< );
---
> String strFileName = AppUtil.getInstance(ReceiveActivity.this).getReceiveQRFilename();
> File file = new File(strFileName);
> if (!file.exists()) {
> try {
> file.createNewFile();
> } catch (Exception e) {
> Toast.makeText(ReceiveActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
> }
> }
> file.setReadable(true, false);
>
> FileOutputStream fos = null;
> try {
> fos = new FileOutputStream(file);
> } catch (FileNotFoundException fnfe) {
> ;
> }
>
> android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ReceiveActivity.this.getSystemService(android.content.Context.CLIPBOARD_SERVICE);
> android.content.ClipData clip = null;
> clip = android.content.ClipData.newPlainText("Receive address", addr);
> clipboard.setPrimaryClip(clip);
>
> if (file != null && fos != null) {
> Bitmap bitmap = ((BitmapDrawable) ivQR.getDrawable()).getBitmap();
> bitmap.compress(Bitmap.CompressFormat.PNG, 0, fos);
>
> try {
> fos.close();
> } catch (IOException ioe) {
> ;
> }
>
> Intent intent = new Intent();
> intent.setAction(Intent.ACTION_SEND);
> intent.setType("image/png");
> if (android.os.Build.VERSION.SDK_INT >= 24) {
> //From API 24 sending FIle on intent ,require custom file provider
> intent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(
> ReceiveActivity.this,
> getApplicationContext()
> .getPackageName() + ".provider", file));
> } else {
> intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
> }
> startActivity(Intent.createChooser(intent, ReceiveActivity.this.getText(R.string.send_payment_code)));
> }
>
647d576
< /*
652d580
< */
666c594
< String url = null; //"https://samouraiwallet.com/support";
---
> String url = "https://samouraiwallet.com/support";
668c596
< url = null; //"http://72typmu5edrjmcdkzuzmv2i4zqru7rjlrcxwtod4nu6qtfsqegngzead.onion/support";
---
> url = "http://72typmu5edrjmcdkzuzmv2i4zqru7rjlrcxwtod4nu6qtfsqegngzead.onion/support";
748,749c676
< final JSONObject jsonObject = APIFactory.getInstance(ReceiveActivity.this)
< .getAddressInfo(new android.util.Pair<>(EnumAddressType.BIP44_LEGACY, addr));
---
> final JSONObject jsonObject = APIFactory.getInstance(ReceiveActivity.this).getAddressInfo(addr);
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/RecoveryWordsActivity.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/RecoveryWordsActivity.kt
19,21d18
< import com.samourai.wallet.onboard.CreateOrRestoreActivity
< import com.samourai.wallet.onboard.OfflineDojoActivityScreen
< import com.samourai.wallet.onboard.SetDojoActivity
34,35c31
< window.statusBarColor = ContextCompat.getColor(this, R.color.networking)
< window.navigationBarColor = ContextCompat.getColor(this, R.color.networking)
---
> window.statusBarColor = ContextCompat.getColor(this, R.color.window)
58,62c54,57
< if (step >= 2) {
< if (AppUtil.getInstance(applicationContext).isOfflineMode())
< startActivity(Intent(this, OfflineDojoActivityScreen::class.java))
< else
< startActivity(Intent(this, SetDojoActivity::class.java))
---
> if (step >= 3) {
> AccessFactory.getInstance(applicationContext).setIsLoggedIn(true)
> TimeOutUtil.getInstance().updatePin()
> AppUtil.getInstance(applicationContext).restartApp()
66,68c61,64
< 0 -> RecoveryWords.newInstance(ArrayList(wordList))
< 1 -> PassphraseFragment.newInstance(passphrase)
< else -> RecoveryWords.newInstance(ArrayList(wordList))
---
> 0 -> RecoveryTemplateDownload()
> 1 -> RecoveryWords.newInstance(ArrayList(wordList))
> 2 -> PassphraseFragment.newInstance(passphrase)
> else -> RecoveryTemplateDownload()
86d81
< /*
110c105
< */
---
>
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/RestoreSeedWalletActivity.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/RestoreSeedWalletActivity.java
28,29d27
< import com.samourai.wallet.onboard.OfflineDojoActivityScreen;
< import com.samourai.wallet.onboard.SetDojoActivity;
51d48
< import java.util.HashMap;
55d51
< import static com.samourai.wallet.R.id.start;
103c99
< getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.networking));
---
> getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.window));
132a129
> ((TextView) forwardButton.getChildAt(0)).setText(R.string.finish);
386c383
< synchronized private void toggleLoading() {
---
> private void toggleLoading() {
410c407
< PayloadUtil.getInstance(RestoreSeedWalletActivity.this).restoreWalletfromJSON(json, skipDojo);
---
> PayloadUtil.getInstance(RestoreSeedWalletActivity.this).restoreWalletfromJSON(json,skipDojo);
415d411
< PrefsUtil.getInstance(RestoreSeedWalletActivity.this).setValue(PrefsUtil.WALLET_SCAN_COMPLETE, false);
442,457c438
< HashMap<String, String> dojoCredsMap = getDojoCredentialsFromBackup(decrypted);
<
< Intent intent;
<
< if (AppUtil.getInstance(getApplicationContext()).isOfflineMode())
< intent = new Intent(getApplicationContext(), OfflineDojoActivityScreen.class);
< else
< intent = new Intent(getApplicationContext(), SetDojoActivity.class);
<
< if (dojoCredsMap != null) {
< intent.putExtra("dojoURL", dojoCredsMap.get("dojoURL"));
< intent.putExtra("explorerURL", dojoCredsMap.get("explorerURL"));
< intent.putExtra("apikey", dojoCredsMap.get("apikey"));
< }
<
< startActivity(intent);
---
> AppUtil.getInstance(RestoreSeedWalletActivity.this).restartApp();
467,484d447
< private HashMap<String, String> getDojoCredentialsFromBackup (String decryptedString) {
< HashMap<String, String> dojoCredsMap = new HashMap<>();
< try {
< JSONObject decryptedJson = new JSONObject(decryptedString);
< JSONObject dojoJson = decryptedJson.getJSONObject("meta").getJSONObject("dojo").getJSONObject("pairing");
< String explorerURL = decryptedJson.getJSONObject("meta").has("explorer_url")
< ? decryptedJson.getJSONObject("meta").getString("explorer_url")
< : "";
<
< dojoCredsMap.put("dojoURL", dojoJson.getString("url"));
< dojoCredsMap.put("apikey", dojoJson.getString("apikey"));
< dojoCredsMap.put("explorerURL", explorerURL);
< } catch (JSONException e) {
< return null;
< }
< return dojoCredsMap;
< }
<
552c515
< PrefsUtil.getInstance(RestoreSeedWalletActivity.this).setValue(PrefsUtil.WALLET_SCAN_COMPLETE, false);
---
> PrefsUtil.getInstance(RestoreSeedWalletActivity.this).setValue(PrefsUtil.FIRST_RUN, true);
555c518
< PrefsUtil.getInstance(RestoreSeedWalletActivity.this).setValue(PrefsUtil.WALLET_SCAN_COMPLETE, false);
---
> PrefsUtil.getInstance(RestoreSeedWalletActivity.this).setValue(PrefsUtil.FIRST_RUN, true);
583,588d545
< if (AppUtil.getInstance(getApplicationContext()).isOfflineMode())
< startActivity(new Intent(getApplicationContext(), OfflineDojoActivityScreen.class));
< else
< startActivity(new Intent(getApplicationContext(), SetDojoActivity.class));
<
< /*
592d548
< */
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/ricochet/RicochetMeta.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/ricochet/RicochetMeta.java
60,61c60,61
< private String SAMOURAI_RICOCHET_TX_FEE_ADDRESS = "bc1qsc887pxce0r3qed50e8he49a3amenemgptakg2";
< private String TESTNET_SAMOURAI_RICOCHET_TX_FEE_ADDRESS = "tb1q6qkv397xf3j48mz4sdh9r3a38r22df5ddct587";
---
> private String SAMOURAI_RICOCHET_TX_FEE_ADDRESS = "bc1q52fzmcdqu07j845q7jnwzw9q68s924wdva3lfz";
> private String TESTNET_SAMOURAI_RICOCHET_TX_FEE_ADDRESS = "tb1qkymumss6zj0rxy9l3v5vqxqwwffy8jjsyhrkrg";
562c562
< public static Pair<List<UTXO>, BigInteger> getHop0UTXO(
---
> private Pair<List<UTXO>, BigInteger> getHop0UTXO(
586a587
> Collections.reverse(utxos);
730,751d730
< }
<
< public static long getFeesFor1Inputs() {
< return SamouraiWallet.bDust.longValue() +
< RicochetMeta.samouraiFeeAmountV1.longValue() + computeHopFee() +
< FeeUtil.getInstance().estimatedFee(1, 3).longValue();
< }
<
< public static long computeHopFee() {
< return computeFeePerHop() * defaultNbHops;
< }
<
< public static long computeFeePerHop() {
< final boolean samouraiFeeViaBIP47 = BIP47Meta.getInstance()
< .getOutgoingStatus(BIP47Meta.strSamouraiDonationPCode) == BIP47Meta.STATUS_SENT_CFM;
< final int hopSz = samouraiFeeViaBIP47
< ? FeeUtil.getInstance().estimatedSize(1, 2)
< : FeeUtil.getInstance().estimatedSize(1, 1);
<
< final long biFeePerKB = FeeUtil.getInstance().getSuggestedFee().getDefaultPerKB().longValue();
< final BigInteger biFeePerHop = FeeUtil.getInstance().calculateFee(hopSz, BigInteger.valueOf(biFeePerKB));
< return biFeePerHop.longValue();
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/SamouraiActivity.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/SamouraiActivity.java
3,5d2
< import static com.samourai.wallet.constants.SamouraiAccountIndex.POSTMIX;
< import static com.samourai.wallet.util.func.WalletUtil.ASHIGARU_PUB_KEY;
<
16,18d12
< import androidx.annotation.Nullable;
< import androidx.appcompat.app.AppCompatActivity;
<
19a14
> import com.samourai.wallet.constants.SamouraiAccountIndex;
24d18
< import com.samourai.wallet.util.network.WebUtil;
26,31c20
< import com.samourai.wallet.util.tech.VerifyPGPSignedClearMessageUtil;
<
< import org.json.JSONObject;
<
< import java.util.concurrent.ExecutorService;
< import java.util.concurrent.Executors;
---
> import com.samourai.wallet.whirlpool.WhirlpoolMeta;
32a22,23
> import androidx.annotation.Nullable;
> import androidx.appcompat.app.AppCompatActivity;
47d37
<
57,58c47,48
< if (getIntent().getExtras().getInt("_account") == POSTMIX) {
< account = POSTMIX;
---
> if (getIntent().getExtras().getInt("_account") == WhirlpoolMeta.getInstance(getApplicationContext()).getWhirlpoolPostmix()) {
> account = WhirlpoolMeta.getInstance(getApplicationContext()).getWhirlpoolPostmix();
67c57
< if (account == POSTMIX) {
---
> if (account == WhirlpoolMeta.getInstance(getApplication()).getWhirlpoolPostmix()) {
132c122
< if (account == POSTMIX) {
---
> if (account == SamouraiAccountIndex.POSTMIX) {
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/SamouraiApplication.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/SamouraiApplication.java
29d28
< import com.samourai.wallet.util.tech.SimpleCallback;
79d77
< /*
88d85
< */
100c97
< "Ashigaru Service",
---
> "Samourai Service",
108d104
< /*
114,117c110
< */
<
<
< //whirlpoolChannel.enableLights(true);
---
> whirlpoolChannel.enableLights(true);
122,123c115,116
< //manager.createNotificationChannel(whirlpoolChannel);
< //manager.createNotificationChannel(whirlpoolNotifications);
---
> manager.createNotificationChannel(whirlpoolChannel);
> manager.createNotificationChannel(whirlpoolNotifications);
170,207c163,171
< SimpleTaskRunner.create().executeAsync(
< true,
< () -> {
< if (tryCount == 1) {
< SamouraiTorManager.INSTANCE.newIdentity();
< } else {
< SamouraiTorManager.INSTANCE.start();
< }
< for (int i = 0; i < 3; ++i) {
< pauseMillis(2_000L);
< if (SamouraiTorManager.INSTANCE.isConnected()) {
< return null;
< }
< }
< pauseMillis(4_000L);
< return null;
< },
< new SimpleCallback<Object>() {
< @Override
< public void onComplete(Object result) {
< if (! SamouraiTorManager.INSTANCE.isConnected()) {
< tryStart(tryCount-1);
< } else {
< Log.i(TAG, "Tor is started");
< }
< }
<
< @Override
< public void onException(Throwable t) {
< if (! SamouraiTorManager.INSTANCE.isConnected()) {
< tryStart(tryCount-1);
< } else {
< Log.i(TAG, "Tor is started");
< }
< }
< }
<
< );
---
> SimpleTaskRunner.create().executeAsync(() -> {
> SamouraiTorManager.INSTANCE.start();
> pauseMillis(3_000L);
> if (! SamouraiTorManager.INSTANCE.isConnected()) {
> tryStart(tryCount-1);
> } else {
> Log.i(TAG, "Tor is started");
> }
> });
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/SamouraiWallet.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/SamouraiWallet.java
11d10
< import org.json.JSONObject;
18d16
< public JSONObject releaseNotes = null;
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/batch/BatchSpendActivity.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/batch/BatchSpendActivity.kt
52d51
< import com.samourai.wallet.send.SendActivity.isPSBT
55a55
> import com.samourai.wallet.send.SendActivity.isPSBT
88d87
< import java.text.DecimalFormatSymbols
385d383
<
387,392d384
< .replace(
< java.lang.String.valueOf(DecimalFormatSymbols(Locale.getDefault()).getGroupingSeparator()),
< ""
< )
<
<
448d439
< /*
452d442
< */
637c627
< var url = "null"; // "https://samouraiwallet.com/support"
---
> var url = "https://samouraiwallet.com/support"
639c629
< url = "null"; // "http://72typmu5edrjmcdkzuzmv2i4zqru7rjlrcxwtod4nu6qtfsqegngzead.onion/support"
---
> url = "http://72typmu5edrjmcdkzuzmv2i4zqru7rjlrcxwtod4nu6qtfsqegngzead.onion/support"
647c637,654
< SendActivity.doFees(this@BatchSpendActivity)
---
> val highFee = FeeUtil.getInstance().highFee
> val normalFee = FeeUtil.getInstance().normalFee
> val lowFee = FeeUtil.getInstance().lowFee
> var message = getText(R.string.current_fee_selection).toString() + " " + FeeUtil.getInstance().suggestedFee.defaultPerKB.toLong() / 1000L + " " + getText(R.string.slash_sat)
> message += "\n"
> message += getText(R.string.current_hi_fee_value).toString() + " " + highFee.defaultPerKB.toLong() / 1000L + " " + getText(R.string.slash_sat)
> message += "\n"
> message += getText(R.string.current_mid_fee_value).toString() + " " + normalFee.defaultPerKB.toLong() / 1000L + " " + getText(R.string.slash_sat)
> message += "\n"
> message += getText(R.string.current_lo_fee_value).toString() + " " + lowFee.defaultPerKB.toLong() / 1000L + " " + getText(R.string.slash_sat)
> val dlg = MaterialAlertDialogBuilder(this@BatchSpendActivity)
> .setTitle(R.string.app_name)
> .setMessage(message)
> .setCancelable(false)
> .setPositiveButton(R.string.ok) { _, _ -> }
> if (!isFinishing) {
> dlg.show()
> }
782c789
< .getSendAddressString(pcode)
---
> .getDestinationAddrFromPcode(pcode)
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/cahoots/SelectCahootsType.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/cahoots/SelectCahootsType.java
17a18
> import com.samourai.wallet.SamouraiWalletConst;
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/FeeUtil.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/FeeUtil.java
3d2
< import static java.lang.Math.max;
65,72d63
< public RawFees getRawFees() {
< return getRawFees(feeRepresentation);
< }
<
< public RawFees getRawFees(final EnumFeeRepresentation feeRepresentation) {
< return rawFeesMap.get(feeRepresentation);
< }
<
217,281d207
< }
<
< public void normalize() {
<
< long feeLow = FeeUtil.getInstance().getLowFee().getDefaultPerKB().longValue();
< long feeMed = FeeUtil.getInstance().getNormalFee().getDefaultPerKB().longValue();
< long feeHigh = FeeUtil.getInstance().getHighFee().getDefaultPerKB().longValue();
<
< /**
< * Finally we don't want to adjust the fees from 1$fee estimator.
< * So this condition is added to avoid that.
< */
< if (!FeeUtil.getInstance().getFeeRepresentation().is1DolFeeEstimator()) {
< if (feeLow == feeMed && feeMed == feeHigh) {
< // offset of low and high
< feeLow = max(1, feeMed * 85L / 100L);
< feeHigh = feeMed * 115L / 100L;
< final SuggestedFee lo_sf = new SuggestedFee();
< lo_sf.setDefaultPerKB(BigInteger.valueOf(feeLow / 1000L * 1000L));
< FeeUtil.getInstance().setLowFee(lo_sf);
< final SuggestedFee hi_sf = new SuggestedFee();
< hi_sf.setDefaultPerKB(BigInteger.valueOf(feeHigh / 1000L * 1000L));
< FeeUtil.getInstance().setHighFee(hi_sf);
< } else if (feeLow == feeMed || feeMed == feeHigh) {
< if (FeeUtil.getInstance().getFeeRepresentation().isBitcoindFeeEstimator()) {
< // offset of mid
< feeMed = (feeLow + feeHigh) / 2L;
< final SuggestedFee mi_sf = new SuggestedFee();
< mi_sf.setDefaultPerKB(BigInteger.valueOf(feeMed / 1000L * 1000L));
< FeeUtil.getInstance().setNormalFee(mi_sf);
< } else if (feeLow == feeMed) {
< feeLow = max(1, feeMed * 85L / 100L);
< final SuggestedFee lo_sf = new SuggestedFee();
< lo_sf.setDefaultPerKB(BigInteger.valueOf(feeLow / 1000L * 1000L));
< FeeUtil.getInstance().setLowFee(lo_sf);
< } else {
< feeHigh = feeMed * 115L / 100L;
< final SuggestedFee hi_sf = new SuggestedFee();
< hi_sf.setDefaultPerKB(BigInteger.valueOf(feeHigh / 1000L * 1000L));
< FeeUtil.getInstance().setHighFee(hi_sf);
< }
< }
< }
<
< /**
< * just for security, avoid inconsistent value
< */
< if (feeLow < 1000L) {
< feeLow = 1000L;
< final SuggestedFee lo_sf = new SuggestedFee();
< lo_sf.setDefaultPerKB(BigInteger.valueOf(feeLow));
< FeeUtil.getInstance().setLowFee(lo_sf);
< }
< if (feeMed < 1000L) {
< feeMed = 1000L;
< final SuggestedFee mi_sf = new SuggestedFee();
< mi_sf.setDefaultPerKB(BigInteger.valueOf(feeMed));
< FeeUtil.getInstance().setNormalFee(mi_sf);
< }
< if (feeHigh < 1000L) {
< feeHigh = 1000L;
< final SuggestedFee hi_sf = new SuggestedFee();
< hi_sf.setDefaultPerKB(BigInteger.valueOf(feeHigh));
< FeeUtil.getInstance().setHighFee(hi_sf);
< }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/broadcast/SpendRicochetTxBroadcaster.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/broadcast/SpendRicochetTxBroadcaster.java
21d20
< import com.samourai.wallet.util.network.BackendApiAndroid;
111c110,111
< final String apiService = BackendApiAndroid.getApiServiceUrl("pushtx/schedule");
---
> String url = WebUtil.getAPIUrl(activity);
> url += "pushtx/schedule";
114c114,120
< result = WebUtil.getInstance(activity).tor_postURL(apiService, nLockTimeObj, null);
---
> if (SamouraiTorManager.INSTANCE.isRequired()) {
> result = WebUtil.getInstance(activity).tor_postURL(url, nLockTimeObj, null);
>
> } else {
> result = WebUtil.getInstance(activity).postURL("application/json", url, nLockTimeObj.toString());
>
> }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/CoinSelectionManagerBottomSheet.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/CoinSelectionManagerBottomSheet.kt
76,82c76
< val stonewallPossible by model.isStonewallPossible.observeAsState()
<
< val txData by model.txData.observeAsState()
< val destinationAmount by model.impliedAmount.observeAsState()
< val feeAggregated by model.feeAggregated.observeAsState()
< val amountToLeaveWallet = (destinationAmount ?: 0L) + (feeAggregated ?: 0L)
< val isMissingAmount = amountToLeaveWallet > txData!!.totalAmountInTxInput
---
> val stonewallPossible by model.isStonewallPossible.observeAsState();
94d87
<
96d88
<
98,101d89
< enable = false
< }
<
< if (selectionType == CUSTOM && isMissingAmount) {
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/preview/BatchPreviewTx.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/preview/BatchPreviewTx.kt
119c119
< .background(Color(0xFF313131), RoundedCornerShape(6.dp))
---
> .background(samouraiLightGreyAccent, RoundedCornerShape(6.dp))
184,185c184,209
< if (txData!!.change > 0L) {
< Row (
---
> Row (
> modifier = Modifier
> .padding(top = 6.dp, bottom = 6.dp)
> .fillMaxWidth(),
> horizontalArrangement = Arrangement.spacedBy(12.dp)
> ) {
> Column {
> Icon(
> painter = painterResource(id = R.drawable.ic_arrow_left_bottom),
> contentDescription = null,
> modifier = Modifier.size(18.dp),
> tint = Color.White
> )
> }
> Column (
> modifier = Modifier,
> horizontalAlignment = Alignment.Start,
> ) {
> Text(
> text = "Returned to wallet",
> color = samouraiTextLightGrey,
> fontSize = 12.sp,
> fontFamily = robotoMonoBoldFont
> )
> }
> Column (
187d210
< .padding(top = 6.dp, bottom = 6.dp)
189c212
< horizontalArrangement = Arrangement.spacedBy(12.dp)
---
> horizontalAlignment = Alignment.End,
191,221c214,219
< Column {
< Icon(
< painter = painterResource(id = R.drawable.ic_arrow_left_bottom),
< contentDescription = null,
< modifier = Modifier.size(18.dp),
< tint = Color.White
< )
< }
< Column (
< modifier = Modifier,
< horizontalAlignment = Alignment.Start,
< ) {
< Text(
< text = "Returned to wallet",
< color = samouraiTextLightGrey,
< fontSize = 12.sp,
< fontFamily = robotoMonoBoldFont
< )
< }
< Column (
< modifier = Modifier
< .fillMaxWidth(),
< horizontalAlignment = Alignment.End,
< ) {
< Text(
< text = FormatsUtil.formatBTC(txData!!.change.coerceAtLeast(0L)),
< color = Color.White,
< fontSize = 12.sp,
< fontFamily = robotoMediumNormalFont
< )
< }
---
> Text(
> text = FormatsUtil.formatBTC(txData!!.change.coerceAtLeast(0L)),
> color = Color.White,
> fontSize = 12.sp,
> fontFamily = robotoMediumNormalFont
> )
224d221
<
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/preview/CustomPreviewTx.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/preview/CustomPreviewTx.kt
135d134
< // security to ensure max 1 utxo for custom postmix, should be never used
143c142
< .background(Color(0xFF313131), RoundedCornerShape(6.dp))
---
> .background(samouraiLightGreyAccent, RoundedCornerShape(6.dp))
316c315
< if (!model.isPostmixAccount || CollectionUtils.isEmpty(customSelectionUtxos)) {
---
> if (!model.isPostmixAccount || customSelectionUtxos!!.isEmpty()) {
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/preview/RicochetCustomPreviewTx.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/preview/RicochetCustomPreviewTx.kt
44,47d43
< import com.samourai.wallet.SamouraiWallet
< import com.samourai.wallet.ricochet.RicochetMeta
< import com.samourai.wallet.ricochet.RicochetMeta.computeHopFee
< import com.samourai.wallet.send.FeeUtil
58a55,56
> import com.samourai.wallet.util.func.TransactionOutPointHelper.retrievesAggregatedAmount
> import com.samourai.wallet.util.func.TransactionOutPointHelper.toTxOutPoints
126a125,129
> val customSelectionUtxos by model.customSelectionUtxos.observeAsState()
> if (model.isPostmixAccount && CollectionUtils.size(customSelectionUtxos) > 1) {
> model.autoLoadCustomSelectionUtxos(1_000_000L)
> model.refreshModel()
> }
131c134
< .background(Color(0xFF313131), RoundedCornerShape(6.dp))
---
> .background(samouraiLightGreyAccent, RoundedCornerShape(6.dp))
181a185
> val sendType by model.impliedSendType.observeAsState()
182a187,190
> val customSelectionAggrAmount = retrievesAggregatedAmount(toTxOutPoints(customSelectionUtxos))
> val isSmallSelectionAmountForRicochet = sendType!!.isRicochet &&
> sendType!!.isCustomSelection &&
> customSelectionAggrAmount < 1_000_000L
188,198c196
<
< val necessaryAmount =
< if (CollectionUtils.isEmpty(customSelectionUtxos)) {
< destinationAmount!! + SamouraiWallet.bDust.toLong() +
< RicochetMeta.samouraiFeeAmountV1.toLong() + computeHopFee() +
< FeeUtil.getInstance().estimatedFee(1, 3).toLong()
< } else {
< amountToLeaveWallet + SamouraiWallet.bDust.toLong()
< }
<
< val isMissingAmount = necessaryAmount > txData!!.totalAmountInTxInput
---
> val isMissingAmount = amountToLeaveWallet > txData!!.totalAmountInTxInput
256c254,280
< text = FormatsUtil.formatBTC(necessaryAmount - txData!!.totalAmountInTxInput),
---
> text = FormatsUtil.formatBTC(amountToLeaveWallet - txData!!.totalAmountInTxInput),
> maxLines = 1,
> color = samouraiAlerts,
> fontSize = 12.sp,
> fontFamily = robotoMediumItalicBoldFont
> )
> }
> }
> }
> if (isSmallSelectionAmountForRicochet) {
> Row (
> horizontalArrangement = Arrangement.spacedBy(12.dp),
> verticalAlignment = Alignment.CenterVertically
> ) {
> Text(
> text = "Sum of inputs must be greater than 0.01 BTC",
> color = samouraiAlerts,
> fontSize = 14.sp,
> fontFamily = robotoMediumItalicBoldFont
> )
> Column(
> modifier = Modifier
> .weight(0.35f),
> horizontalAlignment = Alignment.End,
> ) {
> Text(
> text = FormatsUtil.formatBTC(amountToLeaveWallet - txData!!.totalAmountInTxInput),
326c350
< if (!model.isPostmixAccount || CollectionUtils.isEmpty(customSelectionUtxos)) {
---
> if (!model.isPostmixAccount || customSelectionUtxos!!.isEmpty()) {
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/preview/RicochetPreviewTx.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/preview/RicochetPreviewTx.kt
111c111
< .background(Color(0xFF313131), RoundedCornerShape(6.dp))
---
> .background(samouraiLightGreyAccent, RoundedCornerShape(6.dp))
133c133
< for (utxoPoint in txData!!.selectedUTXOPoints.sortedWith(MyTransactionOutPointAmountComparator(true))) {
---
> for (utxoPoint in txData!!.selectedUTXOPoints.sortedWith(MyTransactionOutPointAmountComparator(false))) {
168c168
< .background(Color(0xFF313131), RoundedCornerShape(6.dp))
---
> .background(samouraiLightGreyAccent, RoundedCornerShape(6.dp))
229,230c229,254
< if (txData!!.change > 0L) {
< Row (
---
> Row (
> modifier = Modifier
> .padding(top = 6.dp, bottom = 6.dp)
> .fillMaxWidth(),
> horizontalArrangement = Arrangement.spacedBy(12.dp)
> ) {
> Column {
> Icon(
> painter = painterResource(id = R.drawable.ic_arrow_left_bottom),
> contentDescription = null,
> modifier = Modifier.size(18.dp),
> tint = Color.White
> )
> }
> Column (
> modifier = Modifier,
> horizontalAlignment = Alignment.Start,
> ) {
> Text(
> text = "Returned to wallet",
> color = samouraiTextLightGrey,
> fontSize = 12.sp,
> fontFamily = robotoMonoBoldFont
> )
> }
> Column (
232d255
< .padding(top = 6.dp, bottom = 6.dp)
234c257
< horizontalArrangement = Arrangement.spacedBy(12.dp)
---
> horizontalAlignment = Alignment.End,
236,266c259,264
< Column {
< Icon(
< painter = painterResource(id = R.drawable.ic_arrow_left_bottom),
< contentDescription = null,
< modifier = Modifier.size(18.dp),
< tint = Color.White
< )
< }
< Column (
< modifier = Modifier,
< horizontalAlignment = Alignment.Start,
< ) {
< Text(
< text = "Returned to wallet",
< color = samouraiTextLightGrey,
< fontSize = 12.sp,
< fontFamily = robotoMonoBoldFont
< )
< }
< Column (
< modifier = Modifier
< .fillMaxWidth(),
< horizontalAlignment = Alignment.End,
< ) {
< Text(
< text = FormatsUtil.formatBTC(txData!!.change.coerceAtLeast(0L)),
< color = Color.White,
< fontSize = 12.sp,
< fontFamily = robotoMediumNormalFont
< )
< }
---
> Text(
> text = FormatsUtil.formatBTC(txData!!.change.coerceAtLeast(0L)),
> color = Color.White,
> fontSize = 12.sp,
> fontFamily = robotoMediumNormalFont
> )
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/preview/SimplePreviewTx.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/preview/SimplePreviewTx.kt
110c110
< .background(Color(0xFF313131), RoundedCornerShape(6.dp))
---
> .background(samouraiLightGreyAccent, RoundedCornerShape(6.dp))
167c167
< .background(Color(0xFF313131), RoundedCornerShape(6.dp))
---
> .background(samouraiLightGreyAccent, RoundedCornerShape(6.dp))
228,229c228,253
< if (txData!!.change > 0L) {
< Row (
---
> Row (
> modifier = Modifier
> .padding(top = 6.dp, bottom = 6.dp)
> .fillMaxWidth(),
> horizontalArrangement = Arrangement.spacedBy(12.dp)
> ) {
> Column {
> Icon(
> painter = painterResource(id = R.drawable.ic_arrow_left_bottom),
> contentDescription = null,
> modifier = Modifier.size(18.dp),
> tint = Color.White
> )
> }
> Column (
> modifier = Modifier,
> horizontalAlignment = Alignment.Start,
> ) {
> Text(
> text = "Returned to wallet",
> color = samouraiTextLightGrey,
> fontSize = 12.sp,
> fontFamily = robotoMonoBoldFont
> )
> }
> Column (
231d254
< .padding(top = 6.dp, bottom = 6.dp)
233c256
< horizontalArrangement = Arrangement.spacedBy(12.dp)
---
> horizontalAlignment = Alignment.End,
235,265c258,263
< Column {
< Icon(
< painter = painterResource(id = R.drawable.ic_arrow_left_bottom),
< contentDescription = null,
< modifier = Modifier.size(18.dp),
< tint = Color.White
< )
< }
< Column (
< modifier = Modifier,
< horizontalAlignment = Alignment.Start,
< ) {
< Text(
< text = "Returned to wallet",
< color = samouraiTextLightGrey,
< fontSize = 12.sp,
< fontFamily = robotoMonoBoldFont
< )
< }
< Column (
< modifier = Modifier
< .fillMaxWidth(),
< horizontalAlignment = Alignment.End,
< ) {
< Text(
< text = FormatsUtil.formatBTC(txData!!.change.coerceAtLeast(0L)),
< color = Color.White,
< fontSize = 12.sp,
< fontFamily = robotoMediumNormalFont
< )
< }
---
> Text(
> text = FormatsUtil.formatBTC(txData!!.change.coerceAtLeast(0L)),
> color = Color.White,
> fontSize = 12.sp,
> fontFamily = robotoMediumNormalFont
> )
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/preview/StonewallPreviewTx.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/preview/StonewallPreviewTx.kt
115c115
< .background(Color(0xFF313131), RoundedCornerShape(6.dp))
---
> .background(samouraiLightGreyAccent, RoundedCornerShape(6.dp))
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/ref/EnumTransactionPriority.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/ref/EnumTransactionPriority.java
122c122
< case VERY_LOW:
---
> case LOW:
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/ref/EnumTxAlert.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/ref/EnumTxAlert.java
3,4c3
< import static com.samourai.wallet.constants.SamouraiAccountIndex.DEPOSIT;
< import static com.samourai.wallet.util.func.AddressHelper.isMyDepositOrPostmixAddress;
---
> import static com.samourai.wallet.util.func.AddressHelper.sendToMyDepositAddress;
23d21
< import com.samourai.wallet.send.SendActivity;
28d25
< import com.samourai.wallet.util.func.AddressHelper;
38d34
< import java.util.Objects;
43,60d38
< SENDING_TO_LEGAL_FUND_DONATION_ADDRESS {
< @Override
< public TxAlertReview createAlert(final ReviewTxModel reviewTxModel) {
< return TxAlertReview.create(
< R.string.tx_alert_title_send_to_donation_address,
< R.string.tx_alert_desc_send_to_donation_address,
< null);
< }
<
< @Override
< public TxAlertReview checkForAlert(final ReviewTxModel reviewTxModel, boolean forInit) {
< if (reviewTxModel.getAddress().equals(SendActivity.DONATION_ADDRESS_MAINNET)
< || reviewTxModel.getAddress().equals(SendActivity.DONATION_ADDRESS_TESTNET)) {
< return createAlert(reviewTxModel);
< }
< return null;
< }
< },
78,82d55
< if (reviewTxModel.getAddress().equals(SendActivity.DONATION_ADDRESS_MAINNET)
< || reviewTxModel.getAddress().equals(SendActivity.DONATION_ADDRESS_TESTNET)) {
< return null;
< }
<
127,131d99
< if (reviewTxModel.getAddress().equals(SendActivity.DONATION_ADDRESS_MAINNET)
< || reviewTxModel.getAddress().equals(SendActivity.DONATION_ADDRESS_TESTNET)) {
< return null;
< }
<
328,340c296,300
<
< if (reviewTxModel.isPostmixAccount()) {
<
< final AddressHelper.AddressInfo myDepositOrPostmixAddress = isMyDepositOrPostmixAddress(
< reviewTxModel.getApplication(),
< reviewTxModel.getAddress(),
< 256);
<
< if (myDepositOrPostmixAddress.isFound() &&
< Objects.equals(myDepositOrPostmixAddress.getAccountIdx(), DEPOSIT) ) {
< return createAlert(reviewTxModel);
< }
<
---
> if (reviewTxModel.isPostmixAccount() &&
> sendToMyDepositAddress(
> reviewTxModel.getApplication(),
> reviewTxModel.getAddress())) {
> return createAlert(reviewTxModel);
344c304,305
< };
---
> }
> ;
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/ReviewTxActivity.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/ReviewTxActivity.kt
96a97,98
> import com.samourai.wallet.util.func.TransactionOutPointHelper.retrievesAggregatedAmount
> import com.samourai.wallet.util.func.TransactionOutPointHelper.toTxOutPoints
172,173d173
< val sendType = reviewTxModel.impliedSendType.value
< val screen = reviewTxModel.currentScreen.value
174a175,180
> val sendType = reviewTxModel.impliedSendType.value
> val customSelectionUtxos = reviewTxModel.customSelectionUtxos.value
> val customSelectionAggrAmount = retrievesAggregatedAmount(toTxOutPoints(customSelectionUtxos))
> val isSmallSingleUtxoForCustomRicochet = sendType!!.isRicochet &&
> sendType!!.isCustomSelection &&
> customSelectionAggrAmount < 1_000_000L
176,177c182,183
< if (!isMissingAmount || !sendType!!.isCustomSelection || sendType!!.isJoinbot || screen != EnumReviewScreen.TX_PREVIEW) {
< when (screen) {
---
> if ((! isSmallSingleUtxoForCustomRicochet && !isMissingAmount) || sendType.isJoinbot) {
> when (reviewTxModel.currentScreen.value) {
183,186d188
< } else {
< if (isMissingAmount && sendType.isCustomSelection) {
< Toast.makeText(this, "missing amount!", Toast.LENGTH_LONG).show()
< }
200,201c202,203
< UpdateStatusBarColorBasedOnDragState(isDraggable = isOnSwipeValidation.value, whiteAlpha = whiteAlpha)
< UpdateNavigationBarColorBasedOnDragState(isDraggable = isOnSwipeValidation.value, whiteAlpha = whiteAlpha)
---
> UpdateStatusBarColorBasedOnDragState(isDraggable = isOnSwipeValidation, whiteAlpha = whiteAlpha)
> UpdateNavigationBarColorBasedOnDragState(isDraggable = isOnSwipeValidation, whiteAlpha = whiteAlpha)
363d364
< val sendType by model.impliedSendType.observeAsState()
364a366,371
> val sendType by model.impliedSendType.observeAsState()
> val customSelectionUtxos by model.customSelectionUtxos.observeAsState()
> val customSelectionAggrAmount = retrievesAggregatedAmount(toTxOutPoints(customSelectionUtxos))
> val isSmallSelectionAmountForRicochet = sendType!!.isRicochet &&
> sendType!!.isCustomSelection &&
> customSelectionAggrAmount < 1_000_000L
367c374
< val backgroundColor = if (account == SamouraiAccountIndex.POSTMIX) Color(0xFF25417b) else Color(0xFF474d59)
---
> val backgroundColor = if (account == SamouraiAccountIndex.POSTMIX) samouraiPostmixSpendBlueButton else samouraiSlateGreyAccent
374c381
< if (!isMissingAmount || !sendType!!.isCustomSelection || sendType!!.isJoinbot || screen != EnumReviewScreen.TX_PREVIEW) {
---
> if ((! isSmallSelectionAmountForRicochet && !isMissingAmount) || sendType!!.isJoinbot) {
449a457,459
> val robotoMonoNormalFont = FontFamily(
> Font(R.font.roboto_mono, FontWeight.Normal)
> )
459c469
< .background(lightenColor(Color(0xFF313131), whiteAlpha), RoundedCornerShape(6.dp))
---
> .background(lightenColor(samouraiLightGreyAccent, whiteAlpha), RoundedCornerShape(6.dp))
554a565,577
>
> val alertReusedGlobal = alertReviews.value!!.get(EnumTxAlert.REUSED_SENDING_ADDRESS_GLOBAL)
> val isReusedAddrGlobal = if (nonNull(alertReusedGlobal))
> alertReusedGlobal!!.isReusedAddress(model.address)
> else false
>
> val alertReusedLocal = alertReviews.value!!.get(EnumTxAlert.REUSED_SENDING_ADDRESS_LOCAL)
> val isReusedAddrLocal = if (nonNull(alertReusedLocal))
> alertReusedLocal!!.isReusedAddress(model.address)
> else false
>
> val isReusedAddr = isReusedAddrGlobal || isReusedAddrLocal
>
556c579,582
< DisplayAddress(address = model.addressLabel)
---
> DisplayAddress(
> address = model.addressLabel,
> addressReused = isReusedAddr
> )
620c646
< addressReused: Boolean = false) {
---
> addressReused: Boolean) {
703c729
< .background(lightenColor(Color(0xFF313131), whiteAlpha), RoundedCornerShape(6.dp))
---
> .background(lightenColor(samouraiLightGreyAccent, whiteAlpha), RoundedCornerShape(6.dp))
975c1001
< .background(lightenColor( Color(0xFF313131), whiteAlpha), RoundedCornerShape(6.dp))
---
> .background(lightenColor(samouraiLightGreyAccent, whiteAlpha), RoundedCornerShape(6.dp))
1245c1271
< Color(0xFF313131).copy(alphaBackground),
---
> samouraiLightGreyAccent.copy(alphaBackground),
1293c1319
< isDraggable: Boolean,
---
> isDraggable: MutableState<Boolean>,
1299c1325
< LaunchedEffect(isDraggable) {
---
> LaunchedEffect(isDraggable.value) {
1307c1333
< isDraggable: Boolean,
---
> isDraggable: MutableState<Boolean>,
1313c1339
< LaunchedEffect(isDraggable) {
---
> LaunchedEffect(isDraggable.value) {
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/ReviewTxAlert.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/ReviewTxAlert.kt
100c100
< .background(Color(0xFF313131), RoundedCornerShape(6.dp))
---
> .background(samouraiLightGreyAccent, RoundedCornerShape(6.dp))
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/ReviewTxFeeManagerBottomSheet.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/ReviewTxFeeManagerBottomSheet.kt
28d27
< import androidx.compose.ui.res.stringResource
137c136
< model.setTransactionPriorityRequested(EnumTransactionPriority.VERY_LOW)
---
> model.setTransactionPriorityRequested(EnumTransactionPriority.LOW)
147c146
< Text(text = EnumTransactionPriority.VERY_LOW.getCaption(FeeUtil.getInstance().feeRepresentation))
---
> Text(text = EnumTransactionPriority.LOW.getCaption(FeeUtil.getInstance().feeRepresentation))
251c250
< text = stringResource(id = R.string.estimated_confirmation_time),
---
> text = "Est confirmation time",
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/ReviewTxModel.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/ReviewTxModel.java
42a43
> import com.samourai.wallet.api.fee.EnumFeeRepresentation;
321c322
< final Map<String, Boolean> content = Maps.newHashMap(seenAddresses.getContent());
---
> final Map<String, Boolean> content = seenAddresses.getContent();
357c358
< setAddress(BIP47Util.getInstance(getApplication()).getSendAddressString(pcode));
---
> setAddress(BIP47Util.getInstance(getApplication()).getDestinationAddrFromPcode(pcode));
420c421
< SimpleTaskRunner.create().executeAsync(true, new Callable<Object>() {
---
> SimpleTaskRunner.create().executeAsync(new Callable<Object>() {
503c504
< SimpleTaskRunner.create().executeAsync(true, new Callable<Long>() {
---
> SimpleTaskRunner.create().executeAsync(new Callable<Long>() {
585,602c586,592
< transactionPriority.postValue(findTransactionPriority(
< feeRates,
< getFeeHighRate().getValue(),
< getFeeLowRate().getValue()));
< }
< }
<
< public static EnumTransactionPriority findTransactionPriority(
< final long feeRates,
< final long feeRatesHigh,
< final long feeRatesLow
< ) {
< if (feeRates >= feeRatesHigh) {
< return EnumTransactionPriority.NEXT_BLOCK;
< } else if (feeRates <= feeRatesLow) {
< return EnumTransactionPriority.VERY_LOW;
< } else {
< return EnumTransactionPriority.NORMAL;
---
> if (feeRates >= getFeeHighRate().getValue()) {
> transactionPriority.postValue(EnumTransactionPriority.NEXT_BLOCK);
> } else if (feeRates <= getFeeLowRate().getValue()) {
> transactionPriority.postValue(EnumTransactionPriority.LOW);
> } else {
> transactionPriority.postValue(EnumTransactionPriority.NORMAL);
> }
762c752
< //addCustomSelectionUtxos(txData.getValue().getSelectedUTXO());
---
> addCustomSelectionUtxos(txData.getValue().getSelectedUTXO());
1373c1363
< //addCustomSelectionUtxos(txData.getValue().getSelectedUTXO());
---
> addCustomSelectionUtxos(txData.getValue().getSelectedUTXO());
1728,1729d1717
< FeeUtil.getInstance().normalize();
<
1732a1721,1769
>
> if (feeLow == feeMed && feeMed == feeHigh) {
> // offset of low and high
> feeLow = max(1, feeMed * 85L / 100L);
> feeHigh = feeMed * 115L / 100L;
> final SuggestedFee lo_sf = new SuggestedFee();
> lo_sf.setDefaultPerKB(BigInteger.valueOf(feeLow / 1000L * 1000L));
> FeeUtil.getInstance().setLowFee(lo_sf);
> final SuggestedFee hi_sf = new SuggestedFee();
> hi_sf.setDefaultPerKB(BigInteger.valueOf(feeHigh / 1000L * 1000L));
> FeeUtil.getInstance().setHighFee(hi_sf);
> } else if (feeLow == feeMed || feeMed == feeHigh) {
> if (FeeUtil.getInstance().getFeeRepresentation() == EnumFeeRepresentation.BLOCK_COUNT) {
> // offset of mid
> feeMed = (feeLow + feeHigh) / 2L;
> final SuggestedFee mi_sf = new SuggestedFee();
> mi_sf.setDefaultPerKB(BigInteger.valueOf(feeMed / 1000L * 1000L));
> FeeUtil.getInstance().setNormalFee(mi_sf);
> } else if (feeLow == feeMed) {
> feeLow = max(1, feeMed * 85L / 100L);
> final SuggestedFee lo_sf = new SuggestedFee();
> lo_sf.setDefaultPerKB(BigInteger.valueOf(feeLow / 1000L * 1000L));
> FeeUtil.getInstance().setLowFee(lo_sf);
> } else {
> feeHigh = feeMed * 115L / 100L;
> final SuggestedFee hi_sf = new SuggestedFee();
> hi_sf.setDefaultPerKB(BigInteger.valueOf(feeHigh / 1000L * 1000L));
> FeeUtil.getInstance().setHighFee(hi_sf);
> }
> }
>
> if (feeLow < 1000L) {
> feeLow = 1000L;
> final SuggestedFee lo_sf = new SuggestedFee();
> lo_sf.setDefaultPerKB(BigInteger.valueOf(feeLow));
> FeeUtil.getInstance().setLowFee(lo_sf);
> }
> if (feeMed < 1000L) {
> feeMed = 1000L;
> final SuggestedFee mi_sf = new SuggestedFee();
> mi_sf.setDefaultPerKB(BigInteger.valueOf(feeMed));
> FeeUtil.getInstance().setNormalFee(mi_sf);
> }
> if (feeHigh < 1000L) {
> feeHigh = 1000L;
> final SuggestedFee hi_sf = new SuggestedFee();
> hi_sf.setDefaultPerKB(BigInteger.valueOf(feeHigh));
> FeeUtil.getInstance().setHighFee(hi_sf);
> }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/review/sendbutton/SwipeSendButton.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/review/sendbutton/SwipeSendButton.kt
63,64d62
< import com.samourai.wallet.util.tech.HapticHelper.Companion.hapticDaDuration
< import com.samourai.wallet.util.tech.HapticHelper.Companion.hapticTadaPattern
196a195
> val hapticTadaPattern = longArrayOf(30, 64, 120, 64)
278c277
< vibratePhone(durationMs = hapticDaDuration, context = context)
---
> vibratePhone(durationMs = 50L, context = context)
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/send/SendActivity.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/send/SendActivity.java
3,13d2
< import static com.samourai.wallet.send.batch.InputBatchSpendHelper.canParseAsBatchSpend;
< import static com.samourai.wallet.send.cahoots.JoinbotHelper.UTXO_COMPARATOR_BY_VALUE;
< import static com.samourai.wallet.send.cahoots.JoinbotHelper.isJoinbotPossibleWithCurrentUserUTXOs;
< import static com.samourai.wallet.util.func.SatoshiBitcoinUnitHelper.getBtcValue;
< import static com.samourai.wallet.util.func.SatoshiBitcoinUnitHelper.getSatValue;
< import static org.apache.commons.lang3.StringUtils.EMPTY;
< import static org.apache.commons.lang3.StringUtils.trim;
< import static java.lang.Math.max;
< import static java.util.Objects.isNull;
< import static java.util.Objects.nonNull;
<
47,52d35
< import androidx.appcompat.widget.SwitchCompat;
< import androidx.appcompat.widget.Toolbar;
< import androidx.constraintlayout.widget.ConstraintLayout;
< import androidx.constraintlayout.widget.Group;
< import androidx.core.content.ContextCompat;
<
66,69d48
< import com.samourai.wallet.api.fee.EnumFeeBlockCount;
< import com.samourai.wallet.api.fee.EnumFeeRate;
< import com.samourai.wallet.api.fee.EnumFeeRepresentation;
< import com.samourai.wallet.api.fee.RawFees;
105d83
< import com.samourai.wallet.util.network.BackendApiAndroid;
118d95
< import org.apache.commons.collections4.CollectionUtils;
147a125,129
> import androidx.appcompat.widget.SwitchCompat;
> import androidx.appcompat.widget.Toolbar;
> import androidx.constraintlayout.widget.ConstraintLayout;
> import androidx.constraintlayout.widget.Group;
> import androidx.core.content.ContextCompat;
155a138,147
> import static com.samourai.wallet.send.batch.InputBatchSpendHelper.canParseAsBatchSpend;
> import static com.samourai.wallet.send.cahoots.JoinbotHelper.UTXO_COMPARATOR_BY_VALUE;
> import static com.samourai.wallet.send.cahoots.JoinbotHelper.isJoinbotPossibleWithCurrentUserUTXOs;
> import static com.samourai.wallet.util.func.SatoshiBitcoinUnitHelper.getBtcValue;
> import static com.samourai.wallet.util.func.SatoshiBitcoinUnitHelper.getSatValue;
> import static java.util.Objects.isNull;
> import static java.util.Objects.nonNull;
> import static org.apache.commons.lang3.StringUtils.EMPTY;
> import static org.apache.commons.lang3.StringUtils.trim;
>
227,229d218
< public final static String DONATION_ADDRESS_MAINNET = "bc1SamouraiDonationAddress_Mainnet";
< public final static String DONATION_ADDRESS_TESTNET = "tb1q930wg92ymtz7a56c5ppfcgcpvphcrzcan53sx5";
<
263,265c252,254
< // joinbotSwitch = sendTransactionDetailsView.getTransactionView().findViewById(R.id.joinbot_switch);
< // joinbotTitle = sendTransactionDetailsView.getTransactionView().findViewById(R.id.joinbot_title);
< // joinbotDesc = sendTransactionDetailsView.getTransactionView().findViewById(R.id.joinbot_desc);
---
> joinbotSwitch = sendTransactionDetailsView.getTransactionView().findViewById(R.id.joinbot_switch);
> joinbotTitle = sendTransactionDetailsView.getTransactionView().findViewById(R.id.joinbot_title);
> joinbotDesc = sendTransactionDetailsView.getTransactionView().findViewById(R.id.joinbot_desc);
281c270
< // premiumAddonsJoinbot = sendTransactionDetailsView.findViewById(R.id.premium_addons_joinbot);
---
> premiumAddonsJoinbot = sendTransactionDetailsView.findViewById(R.id.premium_addons_joinbot);
312c301
< //setUpJoinBot();
---
> setUpJoinBot();
327,334d315
< if (getIntent().getExtras().containsKey("isDonation") && getIntent().getExtras().getBoolean("isDonation")) {
< if (SamouraiWallet.getInstance().isTestNet())
< setToAddress(DONATION_ADDRESS_TESTNET);
< else
< setToAddress(DONATION_ADDRESS_MAINNET);
< toAddressEditText.setEnabled(false);
< }
<
347,348c328,329
< return !AppUtil.getInstance(SendActivity.this).isBroadcastDisabled(); /*&&
< joinbotSwitch.isChecked();*/
---
> return !AppUtil.getInstance(SendActivity.this).isBroadcastDisabled() &&
> joinbotSwitch.isChecked();
393c374
< if (CollectionUtils.isNotEmpty(preselectedUTXOs) && balance < 1_000_000l) {
---
> if (preselectedUTXOs != null && preselectedUTXOs.size() > 0 && balance < 1_000_000l) {
424,426c405
< try {
< premiumAddonsJoinbot.setVisibility(View.GONE);
< } catch (Exception ignored) {}
---
> premiumAddonsJoinbot.setVisibility(View.GONE);
487c466
< if (amount < max(0, balance - (RicochetMeta.samouraiFeeAmountV2.add(BigInteger.valueOf(50000L))).longValue())) {
---
> if (amount < (balance - (RicochetMeta.samouraiFeeAmountV2.add(BigInteger.valueOf(50000L))).longValue())) {
494d472
< SPEND_TYPE = SPEND_RICOCHET;
502d479
< SPEND_TYPE = sendTransactionDetailsView.getStoneWallSwitch().isChecked() ? SPEND_BOLTZMANN : SPEND_SIMPLE;
588c565
< //checkValidForJoinbot();
---
> checkValidForJoinbot();
593c570
< //joinbotSwitch.setChecked(false);
---
> joinbotSwitch.setChecked(false);
612d588
< /*
616d591
< */
657c632
< XManagerClient xManagerClient = new XManagerClient(httpClient, SamouraiWallet.getInstance().isTestNet(), SamouraiTorManager.INSTANCE.isConnected());
---
> XManagerClient xManagerClient = new XManagerClient(httpClient, SamouraiWallet.getInstance().isTestNet(), SamouraiTorManager.INSTANCE.isConnected());
960,964d934
<
< if (amount == balance) {
< SPEND_TYPE = SPEND_SIMPLE;
< }
<
983c953
< /*
---
>
987c957
< */
---
>
1750d1719
< /*
1754d1722
< */
1936c1904,1905
< final String apiServiceUrl = BackendApiAndroid.getApiServiceUrl("pushtx/schedule");
---
> String url = WebUtil.getAPIUrl(SendActivity.this);
> url += "pushtx/schedule";
1939c1908,1915
< result = WebUtil.getInstance(SendActivity.this).tor_postURL(apiServiceUrl, nLockTimeObj, null);
---
> if (SamouraiTorManager.INSTANCE.isRequired()) {
> result = WebUtil.getInstance(SendActivity.this).tor_postURL(url, nLockTimeObj, null);
>
> } else {
> result = WebUtil.getInstance(SendActivity.this).postURL("application/json", url, nLockTimeObj.toString());
>
> }
> // Log.d("SendActivity", "Ricochet staggered result:" + result);
2199c2175
< .getSendAddressString(pcode);
---
> .getDestinationAddrFromPcode(pcode);
2244d2219
< /*
2249d2223
< */
2375c2349
< doFees(SendActivity.this);
---
> doFees();
2378c2352
< } /*else if (id == R.id.action_support) {
---
> } else if (id == R.id.action_support) {
2380c2354
< } */ else {
---
> } else {
2420c2394
< String url = null; //"https://samouraiwallet.com/support";
---
> String url = "https://samouraiwallet.com/support";
2422c2396
< url = null; //"http://72typmu5edrjmcdkzuzmv2i4zqru7rjlrcxwtod4nu6qtfsqegngzead.onion/support";
---
> url = "http://72typmu5edrjmcdkzuzmv2i4zqru7rjlrcxwtod4nu6qtfsqegngzead.onion/support";
2450c2424
< public static void doFees(final SamouraiActivity activity) {
---
> private void doFees() {
2452c2426,2436
< final StringBuilder sb = new StringBuilder();
---
> final SuggestedFee highFee = FeeUtil.getInstance().getHighFee();
> final SuggestedFee normalFee = FeeUtil.getInstance().getNormalFee();
> final SuggestedFee lowFee = FeeUtil.getInstance().getLowFee();
>
> String message = getText(R.string.current_fee_selection) + " " + (FeeUtil.getInstance().getSuggestedFee().getDefaultPerKB().longValue() / 1000L) + " " + getText(R.string.slash_sat);
> message += "\n";
> message += getText(R.string.current_hi_fee_value) + " " + (highFee.getDefaultPerKB().longValue() / 1000L) + " " + getText(R.string.slash_sat);
> message += "\n";
> message += getText(R.string.current_mid_fee_value) + " " + (normalFee.getDefaultPerKB().longValue() / 1000L) + " " + getText(R.string.slash_sat);
> message += "\n";
> message += getText(R.string.current_lo_fee_value) + " " + (lowFee.getDefaultPerKB().longValue() / 1000L) + " " + getText(R.string.slash_sat);
2454,2494c2438
< for (final EnumFeeRepresentation feeRepresentation : EnumFeeRepresentation.values()) {
< sb.append(feeRepresentation.name());
< sb.append(":");
< sb.append(System.lineSeparator());
< final RawFees rawFees = FeeUtil.getInstance().getRawFees(feeRepresentation);
< if (isNull(rawFees) || ! rawFees.hasFee()) {
< sb.append("none");
< sb.append(System.lineSeparator());
< } else {
< switch (feeRepresentation) {
< case NEXT_BLOCK_RATE:
< for (final EnumFeeRate feeRateType : EnumFeeRate.values()) {
< final Integer fee = rawFees.getFee(feeRateType);
< if (nonNull(fee)) {
< sb.append(feeRateType.getRateAsString());
< sb.append(": ");
< sb.append(fee);
< sb.append(" sat/vB");
< sb.append(System.lineSeparator());
< }
< }
< break;
< case BLOCK_COUNT:
< for (final EnumFeeBlockCount blockCount : EnumFeeBlockCount.values()) {
< final Integer fee = rawFees.getFee(blockCount);
< if (nonNull(fee)) {
< sb.append(blockCount.getBlockCount());
< sb.append(": ");
< sb.append(fee);
< sb.append(" sat/vB");
< sb.append(System.lineSeparator());
< }
< }
< break;
< }
<
< }
< sb.append(System.lineSeparator());
< }
<
< final MaterialAlertDialogBuilder dlg = new MaterialAlertDialogBuilder(activity)
---
> final MaterialAlertDialogBuilder dlg = new MaterialAlertDialogBuilder(SendActivity.this)
2496c2440
< .setMessage(sb.toString())
---
> .setMessage(message)
2499,2500c2443
<
< if (!activity.isFinishing()) {
---
> if (!isFinishing()) {
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/service/WalletRefreshWorker.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/service/WalletRefreshWorker.kt
1,159c1,190
< //package com.samourai.wallet.service
< //
< //import android.content.Context
< //import android.content.Intent
< //import android.util.Log
< //import android.widget.Toast
< //import androidx.localbroadcastmanager.content.LocalBroadcastManager
< //import androidx.work.CoroutineWorker
< //import androidx.work.OneTimeWorkRequestBuilder
< //import androidx.work.Operation
< //import androidx.work.WorkManager
< //import androidx.work.WorkerParameters
< //import androidx.work.workDataOf
< //import com.samourai.wallet.SamouraiWallet
< //import com.samourai.wallet.access.AccessFactory
< //import com.samourai.wallet.api.APIFactory
< //import com.samourai.wallet.bip47.BIP47Meta
< //import com.samourai.wallet.bip47.BIP47Util
< //import com.samourai.wallet.crypto.AESUtil
< //import com.samourai.wallet.crypto.DecryptionException
< //import com.samourai.wallet.payload.PayloadUtil
< //import com.samourai.wallet.ricochet.RicochetMeta
< //import com.samourai.wallet.util.CharSequenceX
< //import com.samourai.wallet.util.PrefsUtil
< //import com.samourai.wallet.util.func.WalletUtil
< //import com.samourai.wallet.util.tech.AppUtil
< //import kotlinx.coroutines.Dispatchers
< //import kotlinx.coroutines.async
< //import kotlinx.coroutines.coroutineScope
< //import kotlinx.coroutines.launch
< //import kotlinx.coroutines.withContext
< //import org.apache.commons.lang3.tuple.Pair
< //import org.bitcoinj.core.AddressFormatException
< //import org.bitcoinj.crypto.MnemonicException.MnemonicLengthException
< //import org.json.JSONException
< //import java.io.IOException
< //
< //class WalletRefreshWorker(private val context: Context, private val parameters: WorkerParameters) :
< // CoroutineWorker(context, parameters) {
< //
< //
< // override suspend fun doWork(): Result {
< //
< // val launch: Boolean = parameters.inputData.getBoolean(LAUNCHED, false)
< // val notifTx: Boolean = parameters.inputData.getBoolean(NOTIF_TX, false)
< //
< // AppUtil.getInstance(applicationContext).setWalletLoading(true)
< // APIFactory.getInstance(context).stayingAlive()
< // APIFactory.getInstance(context).initWallet()
< //
< // val _intentDisplay = Intent("com.samourai.wallet.BalanceFragment.DISPLAY")
< // LocalBroadcastManager.getInstance(context).sendBroadcast(_intentDisplay)
< //
< // if (notifTx && !AppUtil.getInstance(context).isOfflineMode) {
< // //
< // // check for incoming payment code notification tx
< // //
< // try {
< // val pcode = BIP47Util.getInstance(context).paymentCode
< // // Log.i("BalanceFragment", "payment code:" + pcode.toString());
< //// Log.i("BalanceFragment", "notification address:" + pcode.notificationAddress().getAddressString());
< // APIFactory.getInstance(context).getNotifAddress(pcode.notificationAddress(SamouraiWallet.getInstance().currentNetworkParams).addressString)
< // } catch (afe: AddressFormatException) {
< // afe.printStackTrace()
< // Toast.makeText(context, "HD wallet error", Toast.LENGTH_SHORT).show()
< // } catch (ex: Exception) {
< // ex.printStackTrace()
< // }
< //
< // loadConnectedPaynyms()
< // val _intent = Intent("com.samourai.wallet.MainActivity2.RESTART_SERVICE")
< // LocalBroadcastManager.getInstance(context).sendBroadcast(_intent)
< // }
< //
< // if (launch) {
< //
< // if (PrefsUtil.getInstance(context).getValue(PrefsUtil.GUID_V, 0) < 4) {
< //
< // Log.i(TAG, "guid_v < 4")
< //
< // try {
< // val _guid = AccessFactory.getInstance(context).createGUID()
< // val _hash = AccessFactory.getInstance(context).getHash(_guid, CharSequenceX(AccessFactory.getInstance(context).pin), AESUtil.DefaultPBKDF2Iterations)
< // PayloadUtil.getInstance(context).saveWalletToJSON(CharSequenceX(_guid + AccessFactory.getInstance().pin))
< // PrefsUtil.getInstance(context).setValue(PrefsUtil.ACCESS_HASH, _hash)
< // PrefsUtil.getInstance(context).setValue(PrefsUtil.ACCESS_HASH2, _hash)
< // Log.i(TAG, "guid_v == 4")
< // } catch (e: MnemonicLengthException) {
< // } catch (e: IOException) {
< // } catch (e: JSONException) {
< // } catch (e: DecryptionException) {
< // }
< // }
< //
< // try {
< // val prevIdx = RicochetMeta.getInstance(context).index
< // APIFactory.getInstance(context).parseRicochetXPUB()
< // if (prevIdx > RicochetMeta.getInstance(context).index) {
< // RicochetMeta.getInstance(context).index = prevIdx
< // }
< // } catch (je: JSONException) {
< // } catch (e: Exception) {
< // }
< // }
< //
< // withContext(Dispatchers.IO) {
< // try {
< // WalletUtil.saveWallet(context)
< // } catch (ignored: Exception) {
< // }
< // }
< //
< // withContext(Dispatchers.Main) {
< // val _intent = Intent("com.samourai.wallet.BalanceFragment.DISPLAY")
< // LocalBroadcastManager.getInstance(context).sendBroadcast(_intent)
< // }
< //
< // AppUtil.getInstance(applicationContext).setWalletLoading(false)
< // val data = workDataOf();
< // return Result.success(data)
< // }
< //
< // private fun loadConnectedPaynyms() {
< // //
< // // check on outgoing payment code notification tx
< // //
< // val outgoingUnconfirmed: List<Pair<String?, String?>> = BIP47Meta.getInstance().outgoingUnconfirmed
< // for (pair in outgoingUnconfirmed) {
< // val confirmations = APIFactory.getInstance(context).getNotifTxConfirmations(pair.right)
< // if (confirmations > 0) {
< // BIP47Meta.getInstance().setOutgoingStatus(pair.left, BIP47Meta.STATUS_SENT_CFM)
< // }
< // if (confirmations == -1) {
< // BIP47Meta.getInstance().setOutgoingStatus(pair.left, BIP47Meta.STATUS_NOT_SENT)
< // }
< // }
< // }
< //
< // companion object {
< // const val LAUNCHED = "LAUNCHED"
< // const val NOTIF_TX = "NOTIF_TX"
< // private const val TAG = "WalletRefreshWorker"
< //
< // fun enqueue(context: Context, notifTx: Boolean = false, launched: Boolean = false): Operation {
< // val workManager = WorkManager.getInstance(context)
< // val workRequest = OneTimeWorkRequestBuilder<WalletRefreshWorker>().apply {
< // setInputData(
< // workDataOf(
< // LAUNCHED to launched,
< // NOTIF_TX to notifTx
< // )
< // )
< // }.build()
< // return workManager.enqueue(workRequest)
< // }
< // }
< //
< //
< //}
\ No newline at end of file
---
> package com.samourai.wallet.service
>
> import android.content.Context
> import android.content.Intent
> import android.util.Log
> import android.widget.Toast
> import androidx.localbroadcastmanager.content.LocalBroadcastManager
> import androidx.work.*
> import com.samourai.wallet.BuildConfig
> import com.samourai.wallet.SamouraiWallet
> import com.samourai.wallet.access.AccessFactory
> import com.samourai.wallet.api.APIFactory
> import com.samourai.wallet.bip47.BIP47Meta
> import com.samourai.wallet.bip47.BIP47Util
> import com.samourai.wallet.crypto.AESUtil
> import com.samourai.wallet.crypto.DecryptionException
> import com.samourai.wallet.hd.HD_WalletFactory
> import com.samourai.wallet.payload.PayloadUtil
> import com.samourai.wallet.ricochet.RicochetMeta
> import com.samourai.wallet.segwit.BIP49Util
> import com.samourai.wallet.segwit.BIP84Util
> import com.samourai.wallet.util.tech.AppUtil
> import com.samourai.wallet.util.CharSequenceX
> import com.samourai.wallet.util.tech.LogUtil
> import com.samourai.wallet.util.PrefsUtil
> import com.samourai.wallet.whirlpool.WhirlpoolMeta
> import kotlinx.coroutines.Dispatchers
> import kotlinx.coroutines.withContext
> import org.apache.commons.lang3.tuple.Pair
> import org.bitcoinj.core.AddressFormatException
> import org.bitcoinj.crypto.MnemonicException.MnemonicLengthException
> import org.json.JSONException
> import java.io.IOException
>
> class WalletRefreshWorker(private val context: Context, private val parameters: WorkerParameters) :
> CoroutineWorker(context, parameters) {
>
>
> override suspend fun doWork(): Result {
>
> val launch: Boolean = parameters.inputData.getBoolean(LAUNCHED, false)
> val notifTx: Boolean = parameters.inputData.getBoolean(NOTIF_TX, false)
>
> AppUtil.getInstance(applicationContext).setWalletLoading(true)
> APIFactory.getInstance(context).stayingAlive()
> APIFactory.getInstance(context).initWallet()
>
> val _intentDisplay = Intent("com.samourai.wallet.BalanceFragment.DISPLAY")
> LocalBroadcastManager.getInstance(context).sendBroadcast(_intentDisplay)
>
> PrefsUtil.getInstance(context).setValue(PrefsUtil.FIRST_RUN, false)
>
> if (notifTx && !AppUtil.getInstance(context).isOfflineMode) {
> //
> // check for incoming payment code notification tx
> //
> try {
> val pcode = BIP47Util.getInstance(context).paymentCode
> // Log.i("BalanceFragment", "payment code:" + pcode.toString());
> // Log.i("BalanceFragment", "notification address:" + pcode.notificationAddress().getAddressString());
> APIFactory.getInstance(context).getNotifAddress(pcode.notificationAddress(SamouraiWallet.getInstance().currentNetworkParams).addressString)
> } catch (afe: AddressFormatException) {
> afe.printStackTrace()
> Toast.makeText(context, "HD wallet error", Toast.LENGTH_SHORT).show()
> } catch (ex: Exception) {
> ex.printStackTrace()
> }
>
> loadConnectedPaynyms()
> val _intent = Intent("com.samourai.wallet.MainActivity2.RESTART_SERVICE")
> LocalBroadcastManager.getInstance(context).sendBroadcast(_intent)
> }
>
> if (launch) {
> if (PrefsUtil.getInstance(context).getValue(PrefsUtil.GUID_V, 0) < 4) {
> Log.i(TAG, "guid_v < 4")
> try {
> val _guid = AccessFactory.getInstance(context).createGUID()
> val _hash = AccessFactory.getInstance(context).getHash(_guid, CharSequenceX(AccessFactory.getInstance(context).pin), AESUtil.DefaultPBKDF2Iterations)
> PayloadUtil.getInstance(context).saveWalletToJSON(CharSequenceX(_guid + AccessFactory.getInstance().pin))
> PrefsUtil.getInstance(context).setValue(PrefsUtil.ACCESS_HASH, _hash)
> PrefsUtil.getInstance(context).setValue(PrefsUtil.ACCESS_HASH2, _hash)
> Log.i(TAG, "guid_v == 4")
> } catch (e: MnemonicLengthException) {
> } catch (e: IOException) {
> } catch (e: JSONException) {
> } catch (e: DecryptionException) {
> }
> }
> if (!PrefsUtil.getInstance(context.applicationContext).getValue(PrefsUtil.XPUB44LOCK, false)) {
> val s = HD_WalletFactory.getInstance(context).get().xpuBs
> APIFactory.getInstance(context).lockXPUB(s[0], 44, null)
> }
> try {
> if (!PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUB49LOCK, false)) {
> val ypub = BIP49Util.getInstance(context).wallet.getAccount(0).ypubstr()
> APIFactory.getInstance(context).lockXPUB(ypub, 49, null)
> }
> if (!PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUB84LOCK, false)) {
> val zpub = BIP84Util.getInstance(context).wallet.getAccount(0).zpubstr()
> APIFactory.getInstance(context).lockXPUB(zpub, 84, null)
> }
> if (!PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUBPRELOCK, false)) {
> val zpub = BIP84Util.getInstance(context).wallet.getAccount(WhirlpoolMeta.getInstance(context).whirlpoolPremixAccount).zpubstr()
> APIFactory.getInstance(context).lockXPUB(zpub, 84, PrefsUtil.XPUBPRELOCK)
> }
> if (!PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUBPOSTLOCK, false)) {
> val zpub = BIP84Util.getInstance(context).wallet.getAccount(WhirlpoolMeta.getInstance(context).whirlpoolPostmix).zpubstr()
> APIFactory.getInstance(context).lockXPUB(zpub, 84, PrefsUtil.XPUBPOSTLOCK)
> }
> if (!PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUBBADBANKLOCK, false)) {
> val zpub = BIP84Util.getInstance(context).wallet.getAccount(WhirlpoolMeta.getInstance(context).whirlpoolBadBank).zpubstr()
> APIFactory.getInstance(context).lockXPUB(zpub, 84, PrefsUtil.XPUBBADBANKLOCK)
> }
> if (!PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUBRICOCHETLOCK, false)) {
> val zpub = BIP84Util.getInstance(context).wallet.getAccount(RicochetMeta.getInstance(context).ricochetAccount).zpubstr()
> APIFactory.getInstance(context).lockXPUB(zpub, 84, PrefsUtil.XPUBRICOCHETLOCK)
> }
> } catch (e: Exception) {
> LogUtil.error(TAG, e.message)
> if (BuildConfig.DEBUG) {
> e.printStackTrace()
> }
> }
> try {
> val prevIdx = RicochetMeta.getInstance(context).index
> APIFactory.getInstance(context).parseRicochetXPUB()
> if (prevIdx > RicochetMeta.getInstance(context).index) {
> RicochetMeta.getInstance(context).index = prevIdx
> }
> } catch (je: JSONException) {
> } catch (e: Exception) {
> }
> }
> withContext(Dispatchers.IO){
> try {
> PayloadUtil.getInstance(context).saveWalletToJSON(CharSequenceX(AccessFactory.getInstance(context).guid + AccessFactory.getInstance(context).pin))
> } catch (ignored: Exception) {
> }
> }
> withContext(Dispatchers.Main) {
> val _intent = Intent("com.samourai.wallet.BalanceFragment.DISPLAY")
> LocalBroadcastManager.getInstance(context).sendBroadcast(_intent)
> }
>
> AppUtil.getInstance(applicationContext).setWalletLoading(false)
> val data = workDataOf();
> return Result.success(data)
> }
>
> private fun loadConnectedPaynyms() {
> //
> // check on outgoing payment code notification tx
> //
> val outgoingUnconfirmed: List<Pair<String?, String?>> = BIP47Meta.getInstance().outgoingUnconfirmed
> // Log.i("BalanceFragment", "outgoingUnconfirmed:" + outgoingUnconfirmed.size());
> for (pair in outgoingUnconfirmed) {
> // Log.i("BalanceFragment", "outgoing payment code:" + pair.getLeft());
> // Log.i("BalanceFragment", "outgoing payment code tx:" + pair.getRight());
> val confirmations = APIFactory.getInstance(context).getNotifTxConfirmations(pair.right)
> if (confirmations > 0) {
> BIP47Meta.getInstance().setOutgoingStatus(pair.left, BIP47Meta.STATUS_SENT_CFM)
> }
> if (confirmations == -1) {
> BIP47Meta.getInstance().setOutgoingStatus(pair.left, BIP47Meta.STATUS_NOT_SENT)
> }
> }
> }
>
> companion object {
> const val LAUNCHED = "LAUNCHED"
> const val NOTIF_TX = "NOTIF_TX"
> private const val TAG = "WalletRefreshWorker"
>
> fun enqueue(context: Context, notifTx: Boolean = false, launched: Boolean = false): Operation {
> val workManager = WorkManager.getInstance(context)
> val workRequest = OneTimeWorkRequestBuilder<WalletRefreshWorker>().apply {
> setInputData(
> workDataOf(
> LAUNCHED to launched,
> NOTIF_TX to notifTx
> )
> )
> }.build()
> return workManager.enqueue(workRequest)
> }
> }
>
>
> }
\ No newline at end of file
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/service/WebSocketHandler.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/service/WebSocketHandler.java
19d18
< import com.samourai.wallet.util.network.BackendApiAndroid;
21d19
< import com.samourai.wallet.util.tech.LogUtil;
161c159
< String wsUrl = BackendApiAndroid.getApiServiceUrl(URL_INV);
---
> String wsUrl = BackendServer.get(testnet).getBackendUrl(onion)+URL_INV;
163c161
< debug("WebSocketHandler", "doInBackground(): connecting WS: " + wsUrl);
---
> debug("WebSocketHandler", "doInBackground(): connecting WS: "+wsUrl);
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/service/WebSocketService.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/service/WebSocketService.java
16d15
< import com.samourai.wallet.util.tech.SimpleTaskRunner;
58,73c57,70
< SimpleTaskRunner.create().executeAsyncAndShutdown(() -> {
< //
< // prune BIP47 lookbehind
< //
< BIP47Meta.getInstance().pruneIncoming();
<
< addrSubs = new ArrayList<>();
< addrSubs.add(AddressFactory.getInstance(context).account2xpub().get(0));
< addrSubs.add(BIP49Util.getInstance(context).getWallet().getAccount(0).xpubstr());
< addrSubs.add(BIP84Util.getInstance(context).getWallet().getAccount(0).xpubstr());
< addrSubs.addAll(Arrays.asList(BIP47Meta.getInstance().getIncomingLookAhead(context)));
< String[] addrs = addrSubs.toArray(new String[addrSubs.size()]);
<
< webSocketHandler = new WebSocketHandler(WebSocketService.this, addrs);
< connectToWebsocketIfNotConnected();
< });
---
> //
> // prune BIP47 lookbehind
> //
> BIP47Meta.getInstance().pruneIncoming();
>
> addrSubs = new ArrayList<String>();
> addrSubs.add(AddressFactory.getInstance(context).account2xpub().get(0));
> addrSubs.add(BIP49Util.getInstance(context).getWallet().getAccount(0).xpubstr());
> addrSubs.add(BIP84Util.getInstance(context).getWallet().getAccount(0).xpubstr());
> addrSubs.addAll(Arrays.asList(BIP47Meta.getInstance().getIncomingLookAhead(context)));
> String[] addrs = addrSubs.toArray(new String[addrSubs.size()]);
>
> webSocketHandler = new WebSocketHandler(WebSocketService.this, addrs);
> connectToWebsocketIfNotConnected();
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/settings/SettingsActivity.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/settings/SettingsActivity.java
8d7
< import androidx.core.content.ContextCompat;
33,34d31
< getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.grey_accent));
<
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/settings/SettingsDetailsFragment.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/settings/SettingsDetailsFragment.kt
25a26
> import com.samourai.wallet.AboutActivity
29d29
< import com.samourai.wallet.SamouraiActivity.CLIPBOARD_SERVICE
36a37
> import com.samourai.wallet.network.dojo.DojoUtil
112c113
< activity?.title = "About"
---
> activity?.title = "Settings | Other"
197,225d197
< val exportPref = findPreference("export") as Preference?
< exportPref!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
< if (SamouraiWallet.getInstance().hasPassphrase(context)) {
< if (HD_WalletFactory.getInstance(context).get() != null && SamouraiWallet.getInstance().hasPassphrase(context)) {
< doBackup(HD_WalletFactory.getInstance(context).get().passphrase)
< }
< } else {
< val builder = MaterialAlertDialogBuilder(requireContext())
< builder.setTitle(R.string.enter_backup_password)
< val view = layoutInflater.inflate(R.layout.password_input_dialog_layout, null)
< val password = view.findViewById<EditText>(R.id.restore_dialog_password_edittext)
< val message = view.findViewById<TextView>(R.id.dialogMessage)
< message.setText(R.string.backup_password)
< builder.setPositiveButton(R.string.confirm) { dialog: DialogInterface, which: Int ->
< val pw = password.text.toString()
< if (pw.length >= AppUtil.MIN_BACKUP_PW_LENGTH && pw.length <= AppUtil.MAX_BACKUP_PW_LENGTH) {
< doBackup(pw)
< } else {
< Toast.makeText(context, R.string.password_error, Toast.LENGTH_SHORT).show()
< }
< dialog.dismiss()
< }
< builder.setNegativeButton(R.string.cancel) { dialog: DialogInterface, which: Int -> dialog.dismiss() }
< builder.setView(view)
< builder.show()
< }
< return@OnPreferenceClickListener true
< }
<
239a212,216
> WhirlpoolMeta.getInstance(requireContext().applicationContext).scode = null
> WhirlpoolNotificationService.stopService(requireContext().applicationContext)
> if (SamouraiTorManager.isConnected()) {
> SamouraiTorManager.start()
> }
343,396d319
< private fun doBackup(passphrase: String) {
< val export_methods = arrayOfNulls<String>(2)
< export_methods[0] = getString(R.string.export_to_clipboard)
< export_methods[1] = "Share"
< MaterialAlertDialogBuilder(requireContext())
< .setTitle(R.string.options_export)
< .setItems(export_methods, DialogInterface.OnClickListener { dialog, which ->
< try {
< PayloadUtil.getInstance(requireContext()).saveWalletToJSON(CharSequenceX(AccessFactory.getInstance(requireContext()).guid + AccessFactory.getInstance(requireContext()).pin))
< } catch (ioe: IOException) {
< } catch (je: JSONException) {
< } catch (de: DecryptionException) {
< } catch (mle: MnemonicLengthException) {
< }
< var encrypted: String? = null
< try {
< encrypted = AESUtil.encryptSHA256(PayloadUtil.getInstance(requireContext()).payload.toString(), CharSequenceX(passphrase))
< } catch (e: Exception) {
< Toast.makeText(requireContext(), e.message, Toast.LENGTH_SHORT).show()
< } finally {
< if (encrypted == null) {
< Toast.makeText(requireContext(), R.string.encryption_error, Toast.LENGTH_SHORT).show()
< return@OnClickListener
< }
< }
< val obj = PayloadUtil.getInstance(requireContext()).putPayload(encrypted, true)
< if (which == 0) {
< AlertDialog.Builder(requireContext())
< .setTitle(R.string.app_name)
< .setMessage(R.string.receive_payload_export)
< .setCancelable(false)
< .setPositiveButton(
< R.string.yes
< ) { dialog, whichButton ->
< val clipboard = requireContext().getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
< var clip: ClipData? = null
< clip = ClipData.newPlainText("Wallet backup", obj.toString())
< clipboard.setPrimaryClip(clip)
< Toast.makeText(requireContext(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
< }.setNegativeButton(
< R.string.no
< ) { dialog, whichButton -> }.show()
< } else {
< val email = Intent(Intent.ACTION_SEND)
< email.putExtra(Intent.EXTRA_SUBJECT, "Ashigaru backup")
< email.putExtra(Intent.EXTRA_TEXT, obj.toString())
< email.type = "message/rfc822"
< startActivity(Intent.createChooser(email, getText(R.string.choose_email_client)))
< }
< dialog.dismiss()
< }
< ).show()
< }
<
476a400,411
> val whirlpoolGUIPref = findPreference("whirlpool_gui") as Preference?
> whirlpoolGUIPref?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
> doWhirlpoolGUIPairing()
> true
> }
>
> val swapsGUIPref = findPreference("swaps_gui") as Preference?
> swapsGUIPref?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
> doSwapsGUIPairing()
> true
> }
>
521c456
< /*
---
>
527d461
< */
543,544c477
< aboutPref?.summary = "v" + BuildConfig.VERSION_NAME
< /*
---
> aboutPref?.summary = "Samourai," + " " + BuildConfig.VERSION_NAME
550d482
< */
782,783c714,715
< val emailAddress = "contact@ashigaru.rs"
< val emailSubject = "Ashigaru support backup"
---
> val emailAddress = "help@samourai.support"
> val emailSubject = "Samourai Wallet support backup"
803,804c735,736
< email.putExtra(Intent.EXTRA_EMAIL, arrayOf("contact@ashigaru.rs"))
< email.putExtra(Intent.EXTRA_SUBJECT, "Ashigaru support backup")
---
> email.putExtra(Intent.EXTRA_EMAIL, arrayOf("help@samourai.support"))
> email.putExtra(Intent.EXTRA_SUBJECT, "Samourai Wallet support backup")
820,821c752,753
< email.data = Uri.parse("mailto:contact@ashigaru.rs")
< email.putExtra(Intent.EXTRA_SUBJECT, "Ashigaru support backup")
---
> email.data = Uri.parse("mailto:help@samourai.support")
> email.putExtra(Intent.EXTRA_SUBJECT, "Samourai Wallet support backup")
925a858,1011
>
> private fun doWhirlpoolGUIPairing() {
>
> fun showQR(pairingObj: JSONObject) {
> val dialog = QRBottomSheetDialog(
> qrData = pairingObj.toString(),
> getString(R.string.whirlpool_pairing), clipboardLabel = getString(R.string.whirlpool_pairing)
> );
> dialog.show(requireActivity().supportFragmentManager, dialog.tag)
> }
>
> val pairingObj = JSONObject()
> val jsonObj = JSONObject()
> val dojoObj = JSONObject()
> try {
> if (DojoUtil.getInstance(requireContext()).dojoParams != null) {
> val params = DojoUtil.getInstance(requireContext()).dojoParams
> val url = DojoUtil.getInstance(requireContext()).getUrl(params)
> val apiKey = DojoUtil.getInstance(requireContext()).getApiKey(params)
> if (url != null && apiKey != null && url.isNotEmpty() && apiKey.isNotEmpty()) {
> dojoObj.put("apikey", apiKey)
> dojoObj.put("url", url)
> }
> }
> jsonObj.put("type", "whirlpool.gui")
> jsonObj.put("version", "3.0.0")
> jsonObj.put("network", if (SamouraiWallet.getInstance().isTestNet) "testnet" else "mainnet")
> val mnemonic = HD_WalletFactory.getInstance(requireContext()).get().mnemonic
> if (SamouraiWallet.getInstance().hasPassphrase(requireContext())) {
> val encrypted = AESUtil.encrypt(mnemonic, CharSequenceX(HD_WalletFactory.getInstance(requireContext()).get().passphrase), AESUtil.DefaultPBKDF2Iterations)
> jsonObj.put("passphrase", true)
> jsonObj.put("mnemonic", encrypted)
> pairingObj.put("pairing", jsonObj)
> if (dojoObj.has("url") && dojoObj.has("apikey")) {
> val apiKey = dojoObj.getString("apikey")
> val encryptedApiKey = AESUtil.encrypt(apiKey, CharSequenceX(HD_WalletFactory.getInstance(requireContext()).get().passphrase))
> dojoObj.put("apikey", encryptedApiKey)
> pairingObj.put("dojo", dojoObj)
> }
> showQR(pairingObj)
> } else {
>
> val builder = MaterialAlertDialogBuilder(requireContext())
> builder.setTitle(getString(R.string.enter_pairing_password))
> val inflater = layoutInflater
> val view = inflater.inflate(R.layout.password_input_dialog_layout, null)
> val password = view.findViewById<EditText>(R.id.restore_dialog_password_edittext)
> val message = view.findViewById<TextView>(R.id.dialogMessage)
> message.setText(R.string.pairing_password)
> builder.setPositiveButton(R.string.confirm) { dialog: DialogInterface, which: Int ->
> val pw = password.text.toString()
> if (pw.length >= AppUtil.MIN_BACKUP_PW_LENGTH && pw.length <= AppUtil.MAX_BACKUP_PW_LENGTH) {
> val encrypted = AESUtil.encrypt(mnemonic, CharSequenceX(pw), AESUtil.DefaultPBKDF2Iterations)
> jsonObj.put("passphrase", false)
> jsonObj.put("mnemonic", encrypted)
> if (dojoObj.has("url") && dojoObj.has("apikey")) {
> val apiKey = dojoObj.getString("apikey")
> val encryptedApiKey = AESUtil.encrypt(apiKey, CharSequenceX(pw))
> dojoObj.put("apikey", encryptedApiKey)
> pairingObj.put("dojo", dojoObj)
> }
> pairingObj.put("pairing", jsonObj)
> showQR(pairingObj)
> }else{
> Toast.makeText(requireContext(), R.string.password_error, Toast.LENGTH_SHORT).show()
> }
> dialog.dismiss()
> }
> builder.setNegativeButton(R.string.cancel) { dialog: DialogInterface, _: Int -> dialog.cancel() }
> builder.setView(view)
> builder.show()
> }
>
> } catch (Er: Exception) {
>
> }
> }
>
> private fun doSwapsGUIPairing() {
>
> fun showQR(pairingObj: JSONObject) {
> val dialog = QRBottomSheetDialog(
> qrData = pairingObj.toString(),
> getString(R.string.swaps_pairing), clipboardLabel = getString(R.string.swaps_pairing)
> );
> dialog.show(requireActivity().supportFragmentManager, dialog.tag)
> }
>
> val pairingObj = JSONObject()
> val jsonObj = JSONObject()
> val dojoObj = JSONObject()
> try {
> if (DojoUtil.getInstance(requireContext()).dojoParams != null) {
> val params = DojoUtil.getInstance(requireContext()).dojoParams
> val url = DojoUtil.getInstance(requireContext()).getUrl(params)
> val apiKey = DojoUtil.getInstance(requireContext()).getApiKey(params)
> if (url != null && apiKey != null && url.isNotEmpty() && apiKey.isNotEmpty()) {
> dojoObj.put("apikey", apiKey)
> dojoObj.put("url", url)
> }
> }
> jsonObj.put("type", "swaps.gui")
> jsonObj.put("version", "1.0.1")
> jsonObj.put("network", if (SamouraiWallet.getInstance().isTestNet) "testnet" else "mainnet")
> val mnemonic = HD_WalletFactory.getInstance(requireContext()).get().mnemonic
> if (SamouraiWallet.getInstance().hasPassphrase(requireContext())) {
> val encrypted = AESUtil.encrypt(mnemonic, CharSequenceX(HD_WalletFactory.getInstance(requireContext()).get().passphrase), AESUtil.DefaultPBKDF2Iterations)
> jsonObj.put("passphrase", true)
> jsonObj.put("mnemonic", encrypted)
> pairingObj.put("pairing", jsonObj)
> if (dojoObj.has("url") && dojoObj.has("apikey")) {
> val apiKey = dojoObj.getString("apikey")
> val encryptedApiKey = AESUtil.encrypt(apiKey, CharSequenceX(HD_WalletFactory.getInstance(requireContext()).get().passphrase))
> dojoObj.put("apikey", encryptedApiKey)
> pairingObj.put("dojo", dojoObj)
> }
> showQR(pairingObj)
> } else {
>
> val builder = MaterialAlertDialogBuilder(requireContext())
> builder.setTitle(getString(R.string.enter_pairing_password))
> val inflater = layoutInflater
> val view = inflater.inflate(R.layout.password_input_dialog_layout, null)
> val password = view.findViewById<EditText>(R.id.restore_dialog_password_edittext)
> val message = view.findViewById<TextView>(R.id.dialogMessage)
> message.setText(R.string.pairing_password)
> builder.setPositiveButton(R.string.confirm) { dialog: DialogInterface, which: Int ->
> val pw = password.text.toString()
> if (pw.length >= AppUtil.MIN_BACKUP_PW_LENGTH && pw.length <= AppUtil.MAX_BACKUP_PW_LENGTH) {
> val encrypted = AESUtil.encrypt(mnemonic, CharSequenceX(pw), AESUtil.DefaultPBKDF2Iterations)
> jsonObj.put("passphrase", false)
> jsonObj.put("mnemonic", encrypted)
> if (dojoObj.has("url") && dojoObj.has("apikey")) {
> val apiKey = dojoObj.getString("apikey")
> val encryptedApiKey = AESUtil.encrypt(apiKey, CharSequenceX(pw))
> dojoObj.put("apikey", encryptedApiKey)
> pairingObj.put("dojo", dojoObj)
> }
> pairingObj.put("pairing", jsonObj)
> showQR(pairingObj)
> }else{
> Toast.makeText(requireContext(), R.string.password_error, Toast.LENGTH_SHORT).show()
> }
> dialog.dismiss()
> }
> builder.setNegativeButton(R.string.cancel) { dialog: DialogInterface, _: Int -> dialog.cancel() }
> builder.setView(view)
> builder.show()
> }
>
> } catch (Er: Exception) {
>
> }
> }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/theme/Color.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/theme/Color.kt
25,33d24
< val samouraiBoxHeaderBackgroundGrey = Color(0xFF363636)
< val samouraiBoxHeaderBackgroundBlack = Color(0xFF242424)
< val samouraiBoxTextLightGrey = Color(0xFFC2C2C2)
< val samouraiBoxTextRed = Color(0xFFC22F2F)
< val samouraiBoxTextOrangeDark = Color(0xFFC2862F)
< val samouraiBoxCheckGreen = Color(0xFF0ECF96)
< val samouraiBoxYellow = Color(0xFFB6B260)
< val samouraiBoxGreenBlueLight = Color(0xFF60B6B2)
< val samouraiBoxGray = Color(0xFF5D5D5D)
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tools/Auth47BottomSheet.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tools/Auth47BottomSheet.kt
283c283
< painter = painterResource(id = R.drawable.qrcode_scan),
---
> painter = painterResource(id = R.drawable.ic_crop_free_white_24dp),
339c339
< var pcodeForAvatar by remember { mutableStateOf("") }
---
> var paynymUrl by remember { mutableStateOf("") }
350c350
< pcodeForAvatar = pcode
---
> paynymUrl = "${WebUtil.PAYNYM_API}${pcode}/avatar"
367,368c367,368
< if (!success && pcodeForAvatar.isNotEmpty()) PicassoImage(
< pcode = pcodeForAvatar,
---
> if (!success && paynymUrl.isNotEmpty()) PicassoImage(
> url = paynymUrl,
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tools/BroadcastHexBottomSheet.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tools/BroadcastHexBottomSheet.kt
334c334
< painter = painterResource(id = R.drawable.qrcode_scan),
---
> painter = painterResource(id = R.drawable.ic_crop_free_white_24dp),
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tools/SignPSBTBottomSheet.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tools/SignPSBTBottomSheet.kt
343c343
< painter = painterResource(id = R.drawable.qrcode_scan),
---
> painter = painterResource(id = R.drawable.ic_crop_free_white_24dp),
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tools/SweepPrivateKey.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tools/SweepPrivateKey.kt
95d94
< import com.samourai.wallet.util.PrivKeyReader
97d95
< import com.samourai.wallet.util.func.FormatsUtil
98a97,98
> import com.samourai.wallet.util.func.FormatsUtil
> import com.samourai.wallet.util.PrivKeyReader
329c329
< painter = if (addressEdit.value.isNullOrEmpty()) painterResource(id = R.drawable.qrcode_scan)
---
> painter = if (addressEdit.value.isNullOrEmpty()) painterResource(id = R.drawable.ic_crop_free_white_24dp)
712c712
< title = stringResource(id = R.string.estimated_confirmation_time),
---
> title = stringResource(id = R.string.estimated_wait_time),
754c754
< text = if (validFees) "$satsPerByte sats/vB" else "_.__",
---
> text = if (validFees) "$satsPerByte sats/b" else "_.__",
873,874c873
< text = title,
< fontSize = 13.sp,
---
> text = title, fontSize = 13.sp,
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tools/ToolsBottomSheet.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tools/ToolsBottomSheet.kt
42d41
< import androidx.compose.ui.graphics.toArgb
240,241d238
<
< window!!.statusBarColor = MaterialTheme.colors.primary.toArgb()
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tools/viewmodels/SweepViewModel.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tools/viewmodels/SweepViewModel.kt
24c24
< import com.samourai.wallet.send.review.ReviewTxModel
---
> import com.samourai.wallet.service.WalletRefreshWorker
26a27,29
> import com.samourai.wallet.util.func.AddressFactory
> import com.samourai.wallet.util.tech.AppUtil
> import com.samourai.wallet.util.network.BackendApiAndroid
30,33d32
< import com.samourai.wallet.util.func.AddressFactory
< import com.samourai.wallet.util.func.WalletRefreshUtil
< import com.samourai.wallet.util.network.BackendApiAndroid
< import com.samourai.wallet.util.tech.AppUtil
36d34
< import kotlinx.coroutines.async
317,346c315,323
< if (FeeUtil.getInstance().feeRepresentation.is1DolFeeEstimator) {
<
< var transactionPriority =
< ReviewTxModel.findTransactionPriority(
< feeForBlocks!!.toLong(),
< FeeUtil.getInstance().highFee.defaultPerKB.toLong(),
< FeeUtil.getInstance().lowFee.defaultPerKB.toLong())
<
< var priorityDesc = transactionPriority!!.getDescription(
< FeeUtil.getInstance().feeRepresentation,
< feeForBlocks!!.toLong(),
< FeeUtil.getInstance().lowFee.defaultPerKB.toLong(),
< FeeUtil.getInstance().normalFee.defaultPerKB.toLong(),
< FeeUtil.getInstance().highFee.defaultPerKB.toLong()
< )
< blocks.postValue(priorityDesc)
< } else {
< if (feeForBlocks != null) {
< if (feeForBlocks <= feeLow.toDouble()) {
< pct = feeLow.toDouble() / feeForBlocks
< nbBlocks = ceil(pct * 24.0).toInt()
< } else if (feeForBlocks >= feeHigh.toDouble()) {
< pct = feeHigh.toDouble() / feeForBlocks
< nbBlocks = ceil(pct * 2.0).toInt()
< if (nbBlocks < 1) {
< nbBlocks = 1
< }
< } else {
< pct = feeMed.toDouble() / feeForBlocks
< nbBlocks = ceil(pct * 6.0).toInt()
---
> if (feeForBlocks != null) {
> if (feeForBlocks <= feeLow.toDouble()) {
> pct = feeLow.toDouble() / feeForBlocks
> nbBlocks = ceil(pct * 24.0).toInt()
> } else if (feeForBlocks >= feeHigh.toDouble()) {
> pct = feeHigh.toDouble() / feeForBlocks
> nbBlocks = ceil(pct * 2.0).toInt()
> if (nbBlocks < 1) {
> nbBlocks = 1
347a325,327
> } else {
> pct = feeMed.toDouble() / feeForBlocks
> nbBlocks = ceil(pct * 6.0).toInt()
349,353d328
< var strBlocks = "$nbBlocks blocks"
< if (nbBlocks > 50) {
< strBlocks = "50+ blocks"
< }
< blocks.postValue(strBlocks)
355c330,334
<
---
> var strBlocks = "$nbBlocks blocks"
> if (nbBlocks > 50) {
> strBlocks = "50+ blocks"
> }
> blocks.postValue(strBlocks)
407,446c386,413
< async {
< delay(1500)
< try {
< val receiveAddress = AddressFactory.getInstance(context).getAddressAndIncrement(receiveAddressType.value).right
< val rbfOptin = PrefsUtil.getInstance(context).getValue(PrefsUtil.RBF_OPT_IN, false)
< val blockHeight = APIFactory.getInstance(context).latestBlockHeight
< val receivers: MutableMap<String, Long> = LinkedHashMap()
< receivers[receiveAddress] = sweepPreview!!.amount
< val bipFormatSupplier: BipFormatSupplier = getBipFormatSupplier(bipFormat.value);
< val outpoints: MutableCollection<MyTransactionOutPoint> = mutableListOf()
< sweepPreview!!.utxos
< .map { unspentOutput: UnspentOutput -> unspentOutput.computeOutpoint(params) }.toCollection(outpoints)
<
< val tr = createTransaction(
< receivers,
< outpoints,
< bipFormatSupplier,
< rbfOptin,
< blockHeight)
<
< transaction = TransactionForSweepHelper.signTransactionForSweep(tr, sweepPreview!!.privKey, params, bipFormatSupplier)
< } catch (e: Exception) {
< throw CancellationException("Sign: ${e.message}")
< }
< try {
< if (transaction != null) {
< val hexTx = TxUtil.getInstance().getTxHex(transaction)
< PushTx.getInstance(context).pushTx(hexTx)
< WalletRefreshUtil.refreshWallet(
< notifTx = false,
< launch = false,
< context = context)
< }
< } catch (e: Exception) {
< throw CancellationException("pushTx : ${e.message}")
< }
< }.invokeOnCompletion {
< broadcastLoading.postValue(false)
< if (it != null) {
< broadcastError.postValue(it.message)
---
> delay(1500)
> try {
> val receiveAddress = AddressFactory.getInstance(context).getAddressAndIncrement(receiveAddressType.value).right
> val rbfOptin = PrefsUtil.getInstance(context).getValue(PrefsUtil.RBF_OPT_IN, false)
> val blockHeight = APIFactory.getInstance(context).latestBlockHeight
> val receivers: MutableMap<String, Long> = LinkedHashMap()
> receivers[receiveAddress] = sweepPreview!!.amount
> val bipFormatSupplier: BipFormatSupplier = getBipFormatSupplier(bipFormat.value);
> val outpoints: MutableCollection<MyTransactionOutPoint> = mutableListOf()
> sweepPreview!!.utxos
> .map { unspentOutput: UnspentOutput -> unspentOutput.computeOutpoint(params) }.toCollection(outpoints)
>
> val tr = createTransaction(
> receivers,
> outpoints,
> bipFormatSupplier,
> rbfOptin,
> blockHeight)
>
> transaction = TransactionForSweepHelper.signTransactionForSweep(tr, sweepPreview!!.privKey, params, bipFormatSupplier)
> } catch (e: Exception) {
> throw CancellationException("Sign: ${e.message}")
> }
> try {
> if (transaction != null) {
> val hexTx = TxUtil.getInstance().getTxHex(transaction)
> PushTx.getInstance(context).pushTx(hexTx)
> WalletRefreshWorker.enqueue(context, notifTx = false, launched = false)
447a415,416
> } catch (e: Exception) {
> throw CancellationException("pushTx : ${e.message}")
448a418
>
450a421,427
> .invokeOnCompletion {
> broadcastLoading.postValue(false)
> if (it != null) {
> broadcastError.postValue(it.message)
> }
> }
>
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tor/kpm/TorKmpManager.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tor/kpm/TorKmpManager.kt
47d46
< import kotlinx.coroutines.Job
51d49
< import okhttp3.internal.wait
239,240c237,238
< fun newIdentity(appContext: Application): Job {
< return appScope.launch {
---
> fun newIdentity(appContext: Application) {
> appScope.launch {
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tor/SamouraiTorManager.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tor/SamouraiTorManager.kt
35,36c35
< return true
< // return PrefsUtil.getInstance(appContext).getValue(PrefsUtil.ENABLE_TOR, false);
---
> return PrefsUtil.getInstance(appContext).getValue(PrefsUtil.ENABLE_TOR, false);
47,50d45
< suspend fun restartSync(): Result<Any?>? {
< return torKmpManager?.torOperationManager?.restart()
< }
<
52c47
< torKmpManager?.torOperationManager?.stopQuietly()
---
> torKmpManager?.torOperationManager?.stopQuietly();
56c51
< torKmpManager?.torOperationManager?.startQuietly()
---
> torKmpManager?.torOperationManager?.startQuietly();
62a58
> @JvmStatic
64,71c60
< torKmpManager?.newIdentity(appContext!!)
< }
<
< suspend fun newIdentitySync() {
< val job = torKmpManager?.newIdentity(appContext!!)
< if (job != null) {
< job.join()
< }
---
> torKmpManager?.newIdentity(appContext!!);
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/tx/TxDetailsActivity.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/tx/TxDetailsActivity.kt
16d15
< import androidx.appcompat.widget.Toolbar
19d17
< import com.google.android.material.appbar.AppBarLayout
30d27
< import com.samourai.wallet.constants.SamouraiAccountIndex
42d38
< import com.samourai.wallet.util.PrefsUtil
91,99d86
< window.statusBarColor = resources.getColor(R.color.balance_blue)
< window.navigationBarColor = resources.getColor(R.color.networking)
< if (intent.hasExtra("_account")) {
< if (intent.getIntExtra("_account", 0) == SamouraiAccountIndex.POSTMIX) {
< findViewById<AppBarLayout>(R.id.appBarLayout4).setBackgroundColor(resources.getColor(R.color.postmix_balance))
< findViewById<Toolbar>(R.id.toolbar).setBackgroundColor(resources.getColor(R.color.postmix_balance))
< window.statusBarColor = resources.getColor(R.color.postmix_balance)
< }
< }
388d374
< true,
489c475
< if (jsonObject.has("vfeerate")) {
---
> if (jsonObject.has("feerate")) {
534a521,524
> if (SamouraiTorManager.isConnected()) {
> SamouraiTorManager.newIdentity()
> }
>
536,537d525
< if (SamouraiTorManager.isConnected())
< SamouraiTorManager.newIdentity()
547,548d534
< if (PrefsUtil.getInstance(applicationContext).getValue(PrefsUtil.BLOCK_EXPLORER_URL, "").isNullOrEmpty())
< menu.findItem(R.id.menu_item_block_explore).setVisible(false)
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/activity/ActivityHelper.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/activity/ActivityHelper.java
3a4
>
15a17
> import androidx.core.app.TaskStackBuilder;
40c42
< return null; // "http://72typmu5edrjmcdkzuzmv2i4zqru7rjlrcxwtod4nu6qtfsqegngzead.onion/support";
---
> return "http://72typmu5edrjmcdkzuzmv2i4zqru7rjlrcxwtod4nu6qtfsqegngzead.onion/support";
42c44
< return null; //"https://samouraiwallet.com/support";
---
> return "https://samouraiwallet.com/support";
77,83c79,99
< final Intent _intent = new Intent(currentActivity, BalanceActivity.class);
< _intent.putExtra("_account", account);
< _intent.putExtra("refresh", true);
< _intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK |
< Intent.FLAG_ACTIVITY_NEW_TASK |
< Intent.FLAG_ACTIVITY_SINGLE_TOP);
< currentActivity.startActivity(_intent);
---
> if (account != 0) {
>
> final Intent balanceHome = new Intent(currentActivity, BalanceActivity.class);
> balanceHome.putExtra("_account", account);
> balanceHome.putExtra("refresh", true);
> final Intent parentIntent = new Intent(currentActivity, BalanceActivity.class);
> parentIntent.putExtra("_account", 0);
> balanceHome.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
> TaskStackBuilder.create(currentActivity.getApplicationContext())
> .addNextIntent(parentIntent)
> .addNextIntent(balanceHome)
> .startActivities();
>
> } else {
> final Intent _intent = new Intent(currentActivity, BalanceActivity.class);
> _intent.putExtra("refresh", true);
> _intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK |
> Intent.FLAG_ACTIVITY_NEW_TASK |
> Intent.FLAG_ACTIVITY_SINGLE_TOP);
> currentActivity.startActivity(_intent);
> }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/func/AddressHelper.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/func/AddressHelper.java
3,6d2
< import static com.samourai.wallet.constants.SamouraiAccountIndex.DEPOSIT;
< import static com.samourai.wallet.constants.SamouraiAccountIndex.POSTMIX;
< import static com.samourai.wallet.util.func.EnumAddressType.BIP84_SEGWIT_NATIVE;
<
46,49c42
< public static AddressInfo isMyDepositOrPostmixAddress(
< final Context context,
< final String address,
< final int scanIndexMargin) {
---
> public static boolean sendToMyDepositAddress(final Context context, final String sendAddress) {
53c46
< final EnumAddressType addressType = EnumAddressType.fromAddress(address);
---
> final EnumAddressType addressType = EnumAddressType.fromAddress(sendAddress);
55a49,50
> final int receiveIndex;
> final int changeIndex;
80,88c75
< if (isNull(addrTypeAsString)) {
< return AddressInfo.createAddressInfo(
< address,
< false,
< null,
< null,
< null,
< addressType.getType());
< }
---
> if (isNull(addrTypeAsString)) return false;
89a77
> final int scanIndexMargin = 64;
95c83
< address,
---
> sendAddress,
101,109c89
< if (indexFound < endIdx && indexFound >= startIdx) {
< return AddressInfo.createAddressInfo(
< address,
< true,
< indexFound,
< isExternal ? 0 : 1,
< DEPOSIT,
< addressType.getType());
< }
---
> if (indexFound < endIdx && indexFound >= startIdx) return true;
116c96
< address,
---
> sendAddress,
122,130c102
< if (indexFound < endIdx && indexFound >= startIdx) {
< return AddressInfo.createAddressInfo(
< address,
< true,
< indexFound,
< isExternal ? 0 : 1,
< DEPOSIT,
< addressType.getType());
< }
---
> if (indexFound < endIdx && indexFound >= startIdx) return true;
132,233c104
< if (addressType == BIP84_SEGWIT_NATIVE) {
< int index = addressFactory.getIndex(WALLET_INDEX.POSTMIX_RECEIVE);
< startIdx = max(0, index - scanIndexMargin);
< endIdx = index + scanIndexMargin;
< indexFound = searchAddressIndex(
< address,
< types[5], // postmix account
< true,
< startIdx,
< endIdx,
< context);
<
< if (indexFound < endIdx && indexFound >= startIdx) {
< return AddressInfo.createAddressInfo(
< address,
< true,
< indexFound,
< 0,
< POSTMIX,
< addressType.getType());
< }
<
< index = addressFactory.getIndex(WALLET_INDEX.POSTMIX_CHANGE);
< startIdx = max(0, index - scanIndexMargin);
< endIdx = index + scanIndexMargin;
< indexFound = searchAddressIndex(
< address,
< types[5], // postmix account
< false,
< startIdx,
< endIdx,
< context);
<
< if (indexFound < endIdx && indexFound >= startIdx) {
< return AddressInfo.createAddressInfo(
< address,
< true,
< indexFound,
< 1,
< POSTMIX,
< addressType.getType());
< }
< }
<
< return AddressInfo.createAddressInfo(
< address,
< false,
< null,
< null,
< null,
< addressType.getType());
< }
<
< public static class AddressInfo {
< private String addr;
< private boolean found;
< private Integer index;
< private Integer chain;
< private Integer addrType;
< private Integer accountIdx;
<
< public static AddressInfo createAddressInfo(
< final String addr,
< final boolean found,
< final Integer index,
< final Integer chain,
< final Integer accountIdx,
< final Integer addrType
< ) {
< final AddressInfo addressInfo = new AddressInfo();
< addressInfo.addr = addr;
< addressInfo.found = found;
< addressInfo.index = index;
< addressInfo.chain = chain;
< addressInfo.accountIdx = accountIdx;
< addressInfo.addrType = addrType;
< return addressInfo;
< }
<
< public String getAddr() {
< return addr;
< }
<
< public boolean isFound() {
< return found;
< }
<
< public Integer getIndex() {
< return index;
< }
<
< public Integer getChain() {
< return chain;
< }
<
< public Integer getAccountIdx() {
< return accountIdx;
< }
<
< public Integer getAddrType() {
< return addrType;
< }
---
> return false;
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/func/BatchSendUtil.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/func/BatchSendUtil.java
54c54
< .getSendAddressString(pcode);
---
> .getDestinationAddrFromPcode(pcode);
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/func/PayNymUtil.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/func/PayNymUtil.kt
4,5c4
< import android.util.Log
< import com.google.gson.Gson
---
> import com.samourai.wallet.access.AccessFactory
9d7
< import com.samourai.wallet.bip47.paynym.WebUtil
12,22c10
< import com.samourai.wallet.paynym.api.PayNymApiService
< import com.samourai.wallet.paynym.models.NymResponse
< import com.samourai.wallet.util.PrefsUtil
< import kotlinx.coroutines.CancellationException
< import org.apache.commons.lang3.StringUtils
< import org.apache.commons.lang3.StringUtils.defaultIfBlank
< import org.json.JSONException
< import org.json.JSONObject
<
<
< const val TAG = "PayNymUtil"
---
> import com.samourai.wallet.util.CharSequenceX
25,28d12
< synPayNym(pcode, true, context)
< }
<
< fun synPayNym(pcode : String?, saveWallet : Boolean, context : Context) {
37,40c21,25
< val addr = BIP47Util.getInstance(context).getReceivePubKey(payment_code, i)
< BIP47Meta.getInstance().idx4AddrLookup[addr] = i
< BIP47Meta.getInstance().pCode4AddrLookup[addr] = payment_code.toString()
< addrs.add(addr)
---
> BIP47Meta.getInstance().idx4AddrLookup[BIP47Util.getInstance(context)
> .getReceivePubKey(payment_code, i)] = i
> BIP47Meta.getInstance().pCode4AddrLookup[BIP47Util.getInstance(context)
> .getReceivePubKey(payment_code, i)] = payment_code.toString()
> addrs.add(BIP47Util.getInstance(context).getReceivePubKey(payment_code, i))
57,60c42,49
< val sendPubKey = BIP47Util.getInstance(context).getSendPubKey(payment_code, i)
< BIP47Meta.getInstance().idx4AddrLookup[sendPubKey] = i
< BIP47Meta.getInstance().pCode4AddrLookup[sendPubKey] = payment_code.toString()
< addrs.add(sendPubKey)
---
> val sendAddress = BIP47Util.getInstance(context).getSendAddress(payment_code, i)
> // Log.i("PayNymDetailsActivity", "sync send to " + i + ":" + sendAddress.getSendECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString());
> // BIP47Meta.getInstance().setOutgoingIdx(payment_code.toString(), i);
> BIP47Meta.getInstance().idx4AddrLookup[BIP47Util.getInstance(context)
> .getSendPubKey(payment_code, i)] = i
> BIP47Meta.getInstance().pCode4AddrLookup[BIP47Util.getInstance(context)
> .getSendPubKey(payment_code, i)] = payment_code.toString()
> addrs.add(BIP47Util.getInstance(context).getSendPubKey(payment_code, i))
70d58
<
72,228c60,65
<
< if (saveWallet) {
< WalletUtil.saveWallet(context)
< }
< }
<
< suspend fun executeFeaturePayNymUpdate(context : Context) {
< var obj = JSONObject()
< obj.put("code", BIP47Util.getInstance(context).paymentCode.toString())
< var res = WebUtil.getInstance(context).postURL("application/json", null, WebUtil.PAYNYM_API + "api/v1/token", obj.toString())
< var responseObj = JSONObject(res)
< if (responseObj.has("token")) {
< val token = responseObj.getString("token")
< val sig = MessageSignUtil.getInstance(context).signMessage(BIP47Util.getInstance(context).notificationAddress.ecKey, token)
< obj = JSONObject()
< obj.put("nym", BIP47Util.getInstance(context).paymentCode.toString())
< obj.put("code", BIP47Util.getInstance(context).featurePaymentCode.toString())
< obj.put("signature", sig)
<
< res = WebUtil.getInstance(context).postURL("application/json", token, WebUtil.PAYNYM_API + "api/v1/nym/add", obj.toString())
< responseObj = JSONObject(res)
< if (responseObj.has("segwit") && responseObj.has("token")) {
< PrefsUtil.getInstance(context).setValue(PrefsUtil.PAYNYM_FEATURED_SEGWIT, true)
< } else if (responseObj.has("claimed") && responseObj.getBoolean("claimed") == true) {
< PrefsUtil.getInstance(context).setValue(PrefsUtil.PAYNYM_FEATURED_SEGWIT, true)
< }
< }
< }
<
< suspend fun isClaimedAndFeaturedPayNym(context : Context) : Triple<Boolean, Boolean, String> {
< val pcode = BIP47Util.getInstance(context).paymentCode.toString()
< val nymInfo = getNymInfoOffline(pcode, context)
< var strNymName : String = ""
< if (nymInfo.has("nymName")) {
< strNymName = nymInfo.getString("nymName")
< BIP47Meta.getInstance().setName(pcode, strNymName)
< if (FormatsUtil.getInstance().isValidPaymentCode(BIP47Meta.getInstance().getLabel(pcode))) {
< BIP47Meta.getInstance().setLabel(pcode, strNymName)
< }
< }
< var featured : Boolean = false
< if (nymInfo.has("segwit") && nymInfo.getBoolean("segwit")) {
< featured = true
< }
<
< var claimed = isClaimedPayNym(pcode, nymInfo)
<
< return Triple(claimed, featured, strNymName)
< }
<
< suspend fun isClaimedPayNym(pcode : String, nymInfo: JSONObject): Boolean {
<
< var claimed : Boolean = false
< if (nymInfo.has("codes")) {
< val codeArray = nymInfo.getJSONArray("codes")
<
< for (i in 0 until codeArray.length()) {
< val codeInfo: JSONObject = codeArray.getJSONObject(i)
< if (codeInfo.has("code") && StringUtils.equals(codeInfo.getString("code"), pcode)) {
< claimed = codeInfo.has("claimed") && codeInfo.getBoolean("claimed");
< break;
< }
< }
< }
<
< return claimed
< }
<
< suspend fun getNymInfoOffline(pcode: String, context: Context): JSONObject {
< val obj = JSONObject()
< obj.put("nym", pcode)
< val res = WebUtil.getInstance(context)
< .postURL("application/json", null, WebUtil.PAYNYM_API + "api/v1/nym", obj.toString())
< return JSONObject(res)
< }
<
< suspend fun getNymInfo(pcode: String, context: Context): JSONObject {
<
< var nymInfo : JSONObject = JSONObject()
< val apiPayNymApiService = PayNymApiService(pcode, context)
<
< try {
< val nymResponse = apiPayNymApiService.getNymInfo()
< if (nymResponse.isSuccessful) {
< nymInfo = JSONObject(nymResponse.body?.string())
< }
< } catch (ex: Exception) {
< throw CancellationException(ex.message)
< }
< return nymInfo;
< }
<
< suspend fun claim(context : Context) : Pair<Boolean, String> {
<
< val strPaymentCode = BIP47Util.getInstance(context).paymentCode.toString()
< val apiPayNymApiService = PayNymApiService(strPaymentCode, context)
<
< try {
< val response = apiPayNymApiService.claim()
< if (response.isSuccessful) {
< val nymResponse = apiPayNymApiService.getNymInfo()
< if (nymResponse.isSuccessful) {
< try {
< val data = JSONObject(nymResponse.body?.string())
< PayloadUtil.getInstance(context).serializePayNyms(data)
< val nym = if (data.has("nymName")) data.getString("nymName") else ""
< return Pair(true, nym)
< } catch (ex: Exception) {
< throw CancellationException(ex.message)
< }
< }
< }
< } catch (ex: Exception) {
< throw CancellationException(ex.message)
< }
< return Pair(false, "")
< }
<
< suspend fun reinitBIP47Meta(context: Context) : Boolean {
< try {
<
< val pcodeLabelsToRestore = BIP47Meta.getInstance().copyOfPcodeLabels
<
< val pcode = BIP47Util.getInstance(context).paymentCode.toString()
< var jsonObject = getNymInfo(pcode, context)
< if (jsonObject.has("empty") || !jsonObject.has("codes")) {
< return true
< }
< val nym = Gson().fromJson(jsonObject.toString(), NymResponse::class.java);
< BIP47Meta.getInstance().partialClearOnRestoringWallet()
<
< nym.following?.let { codes ->
< codes.forEach { paynym ->
< BIP47Meta.getInstance().setSegwit(paynym.code, paynym.segwit)
< BIP47Meta.getInstance().setName(paynym.code, paynym.nymName)
< val pname = defaultIfBlank(pcodeLabelsToRestore.get(paynym.code), paynym.nymName)
< BIP47Meta.getInstance().setLabel(paynym.code, pname)
< }
< val followings = ArrayList(codes.distinctBy { it.code }.map { it.code })
< BIP47Meta.getInstance().setFollowings(followings)
< }
< nym.followers?.let { codes ->
< codes.forEach { paynym ->
< BIP47Meta.getInstance().setSegwit(paynym.code, paynym.segwit)
< BIP47Meta.getInstance().setName(paynym.code, paynym.nymName)
< val pname = defaultIfBlank(pcodeLabelsToRestore.get(paynym.code), paynym.nymName)
< BIP47Meta.getInstance().setLabel(paynym.code, pname)
< }
< }
<
< PayloadUtil.getInstance(context).serializePayNyms(jsonObject);
< } catch (e: JSONException) {
< Log.e(TAG, "issue on registerPayNymContact", e)
< return false
< }
< return true
< }
---
> PayloadUtil.getInstance(context).saveWalletToJSON(
> CharSequenceX(
> AccessFactory.getInstance(context).guid + AccessFactory.getInstance(context).pin
> )
> )
> }
\ No newline at end of file
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/func/WalletUtil.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/func/WalletUtil.java
5d4
< import com.samourai.wallet.SamouraiActivity;
8,9d6
< import com.samourai.wallet.stealth.StealthModeController;
< import com.samourai.wallet.tor.SamouraiTorManager;
11,12d7
< import com.samourai.wallet.util.TimeOutUtil;
< import com.samourai.wallet.whirlpool.service.WhirlpoolNotificationService;
16,69d10
< public static final String ASHIGARU_PUB_KEY =
< "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
< "Comment: https://keybase.io/ashigarudev\n" +
< "Version: Keybase Go 6.3.1 (linux)\n" +
< "\n" +
< "xsFNBGZdzx4BEADmL1E5gLoHtAd+N9Cw22VbnD47em9Hn946aDeB90pbrx02m8TW\n" +
< "Acji5VOOmN1CNg2EomG0aGk6eox1TZkisYsu5rTCmpQX36CQ6/LvUFh8MTYF38kW\n" +
< "wukNxE93wrXz/emk2yW/jeos6XlQ6/iJmom4bRCHDLxstFn14ICitr2zKysAOHkC\n" +
< "iutQacwsGSLImi/7YEzQrIAi4WeTGrScyEFaJ0BxOQ4lzZeQw3Me+ESufZDOfB6+\n" +
< "u8wsZzqVP5drp/AStbhGPhkYXbHJGikgVDVxxm/C9Yy/jhcQGUPSEFqXREeFncTM\n" +
< "w7q3M5YG7Rl7m2VPEElNkZRYBI7fa5G5E6Iy01Y4/KxyutRwOf/DZHUaK/VQQQne\n" +
< "HJzH58PvISPvswZzJWKN3mHiNGrbWGyBcvJOXlfbekLbRML8I28usKnSDWbHdkWc\n" +
< "9Ls8P+H62TcY7npdGRvZAGIcM11BqGp66fndc911HDbX3/0IPp1DJEnpLn46gQqs\n" +
< "3GJ6rMTBbt++krIFam1/kIr3Atp5EBqoSgAvxY5Xk+OUsYaa/K3VBQONpI2f7qJZ\n" +
< "HN9GpqszwF2eeu1vKB/CRxISRQLjklVBssiZ2Zez7PZ470Ses1V7jK2tWGqzf5sG\n" +
< "C0Tpp53WqFHtn4u/YuRtPQJtO0FHsc82mZbynoCO5YhNSh1mivPQoxPj0QARAQAB\n" +
< "zQxBc2hpZ2FydSBEZXbCwXEEEwEKACUFAmZdzx4JEKE4BrH6KmdrAhsDBQsJCAcD\n" +
< "BRUKCQgLBRYCAwEAAAD0txAAzpXmxtqVRLxEEdUBx1kxp1kE8kDJAhBraX5VXGOv\n" +
< "HuThhcr3j5Esj4IOGcsiV5S9nRNPu+hjjTX8AoOVLQcfU0jymrNRBXLQcd7L03Jj\n" +
< "0vG3sb7HOVbnQdGAwCrabb941BB3smitsYqI/Xz12CjavsONSp6wImt+jVHsAYC6\n" +
< "y1xew4cBkPL9VmzKabTGNTV+wPe7xHSdptdAvK98EWFZ+Yq3ut/rt4mnqr35OQWW\n" +
< "qDcAiAqKndqJXVZklDOvdQ654VPsBlJG4V+K4evZ7ECUc4gRVWWe5Ijl9z0UGopv\n" +
< "FTkeTn9GnyHRZgLYooHkqd3oith/1fweldatvRGIXpdA1W02Tn7I0imjvzgBNDVq\n" +
< "MS3rCp8kFFDtcshpASbtXChiloMFaw1+VDymT7sF81S5obbsJYRRkt2Qo+xM3B2n\n" +
< "t0gZDMuLAJ2Er9VXxpcyrjl8U+Us8atbx7x4UyPaZJe4zj8nZYZly/uVZQ8JL/Nc\n" +
< "zMg8ES9c8LV9ZcSlsIgX8VT6omxlSzWZNtfswBrXMUruxJgc7WKn1I6JMFbeRUG5\n" +
< "fLtjLyn4/KufW+Liiq4RKcRQb/rxUaT+e7tzY90y4MqTzLD7kbVhCRx5RVBY5bZD\n" +
< "2pFtch6CPVnZx/EHjR3Yd2zZgbDCVSIEEA6y2QS3aMhHXu1orgjVayOWVTINZE0y\n" +
< "K3POwU0EZl3PHgEQAOOzDEJRk8paHDXqNGYiFiQZCxX3CIOK3+DR+zsS8oq4AtXT\n" +
< "R7WUBDRACwUkDpNhybmkpEWH6B3zdsZPaGJ80ApTImWXc6KMJagcAJPVrwSGttOb\n" +
< "zQHCsbsVfS3xXQ4G3uxncLd7Ck+fesR0GVsfJ4HsTOZaKmbuUYFifa4PevwEeYKR\n" +
< "AcPdfcx7dTRd18XBaBPLNRzbUfck1rCIiO9QXR6oVbUYBlOKPVDYMjgrav4hd2s2\n" +
< "BxWNLXxkE3MsyTSQ/+B8ty9Sz0C0aDrRRs5lA0/07hF9C3Wnv8op5XsUkO5eT7RD\n" +
< "1PeWk+WiQURcQhAJsmrxjG7rXWQWaU8QR095Ldd1VRZXzPoLx8+iTNWqNRj/VuWw\n" +
< "vhThYuWIP+RJTAV4kx/Mi8Os1dkV0KIKYQYsu+i0d7UBqL4LzCoY332Z/vJiaoVT\n" +
< "+Aa4T7+/hgoG0VYF5ddSyDZv+CwUOzLO7fh/Tg4Jv1CpHKgwq4NELf6G7SVjrnKH\n" +
< "LNd/JULHDMTpl6/RFn0rrwb/phmfQz0cbHU3ZXUJU5m9aqvjhdjV31+UP+Re0EBB\n" +
< "JKDTHqzggTfPtpu8+nIRrfxm8pyHHxmt4pa4wUYujLnySLyPpMYLuAi3U7FUSHyo\n" +
< "F3eZB1SeQ+9rQuZSRlvjXJTdNBDDUnJR9CiKC6K78jHKXHd5v7LPWh86g7SpABEB\n" +
< "AAHCwXYEGAEKACAWIQREX4B5lvcFhrcVx7ihOAax+ipnawUCZl3PHgIbDAAKCRCh\n" +
< "OAax+ipna9/OD/0bHstAeNKkUezn8QbI8ZuRXgkrcPo0EQ3dUNO6ZbyhqFUiM8Vt\n" +
< "1syF2vX72+BNewwFsOAWHrDTRSZ09dO+M1c58I+Lr1AVP14jfYQ0mmPGY8ND9sk5\n" +
< "WDheZjCbO6OJ55yQzC/ZTEra1Pxi3yWqcneyG3yX4z4ih3BazYIH3MR3EaSLVLjd\n" +
< "eo3TqviWsBE7upKI1ipKf58l/0JoYWWWyVSVbEk/kjHlod19NjHzBvxzAX7I17Co\n" +
< "+TMduAb2wrwVOqdDzOTS/X/KOAs7Q643rTgz9YqC2V/k9FLDKQIgqUvsADTnZtwF\n" +
< "1fzL3U/xcJdh46Yy3lmyi2e9Rt6oVSGTaRiSWSlPYGAgiLYiHGTpLhpAmupNGdaj\n" +
< "tJ0PZPoFehQ7zW75tOml1/8AIwUgzJsQHSKe3UCG7uSpXWT0sE4trfF71O0y0zoH\n" +
< "hJZZq0X9O6iC3qLOGi8l4ZmhTJhBd3YlPqtugHuQWSiBABR2EoCxrhgbu0W5+Dp/\n" +
< "db/0DMdwPhIwWwi1j6E3YKqQiz3q+mjUflUFiskJUeaYQe+YaeXJ43bZ4WPXZcfy\n" +
< "5WEKWZypGiuhirhfSrdmt4EPWQ3fR2j7/RafEpMsF9cWDvAoAvQQK3VM/EoCcj12\n" +
< "qbgNKNuFv/4hw+BF2AUIM3SojZ6yqaNw2NByy3zKd5Wx1U4Pd6OY4Jcrxg==\n" +
< "=iJA5\n" +
< "-----END PGP PUBLIC KEY BLOCK-----\n";
<
82,96d22
< }
<
< public static void stop(final SamouraiActivity activity) {
< if (SamouraiTorManager.INSTANCE.isConnected()) {
< SamouraiTorManager.INSTANCE.stop();
< }
< if (WhirlpoolNotificationService.isRunning(activity)) {
< WhirlpoolNotificationService.stopService(activity);
< }
< TimeOutUtil.getInstance().reset();
< if (StealthModeController.INSTANCE.isStealthEnabled(activity)) {
< StealthModeController.INSTANCE.enableStealth(activity);
< }
< activity.finishAffinity();
< activity.finish();
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/network/BackendApiAndroid.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/network/BackendApiAndroid.java
3,4d2
< import static org.apache.commons.lang3.StringUtils.strip;
<
15a14
> import com.samourai.wallet.util.network.WebUtil;
18,19d16
< public static final boolean FULL_DOJO_MODE_ONLY = true;
< public static final String URI_SEP = "/";
22c19
< public static BackendApi getInstance(final Context ctx) {
---
> public static BackendApi getInstance(Context ctx) {
26c23,24
< if (FULL_DOJO_MODE_ONLY || (DojoUtil.getInstance(ctx).getDojoParams() != null)) {
---
> boolean useDojo = (DojoUtil.getInstance(ctx).getDojoParams() != null);
> if (useDojo) {
28,29c26,28
< final String dojoApiKey = APIFactory.getInstance(ctx).getAppToken();
< backendApi = BackendApi.newBackendApiDojo(httpClient, getApiBaseUrl(), dojoApiKey);
---
> String dojoApiKey = APIFactory.getInstance(ctx).getAppToken();
> String dojoUrl = testnet ? WebUtil.SAMOURAI_API2_TESTNET_TOR : WebUtil.SAMOURAI_API2_TOR;
> backendApi = BackendApi.newBackendApiDojo(httpClient, dojoUrl, dojoApiKey);
42,51d40
< }
<
< public static String getApiBaseUrl() {
< return SamouraiWallet.getInstance().isTestNet()
< ? WebUtil.SAMOURAI_API2_TESTNET_TOR
< : WebUtil.SAMOURAI_API2_TOR;
< }
<
< public static String getApiServiceUrl(final String service) {
< return strip(getApiBaseUrl(), URI_SEP) + URI_SEP + strip(service, URI_SEP);
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/network/BlockExplorerUtil.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/network/BlockExplorerUtil.java
5d4
< import com.samourai.wallet.util.PrefsUtil;
8c7,9
< /*
---
>
> private static String strMainNetClearExplorer = "https://m.oxt.me/";
> private static String strMainNetTorExplorer = "http://oxtmblv4v7q5rotqtbbmtbcc5aa5vehr72eiebyamclfo3rco5zm3did.onion/";
11,13d11
< private static String strMainNetClearExplorer = strTestNetClearExplorer; // "https://m.oxt.me/";
< private static String strMainNetTorExplorer = strTestNetTorExplorer; // "http://oxtmblv4v7q5rotqtbbmtbcc5aa5vehr72eiebyamclfo3rco5zm3did.onion/";
< */
29,30c27,29
< return null;
< /*
---
>
> String ret = null;
>
51d49
< */
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/network/WebUtil.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/network/WebUtil.java
3d2
< import static com.samourai.wallet.util.tech.LogUtil.debug;
6,7d4
< import static org.apache.commons.lang3.StringUtils.EMPTY;
<
10,11d6
< import androidx.annotation.NonNull;
<
22d16
< import com.samourai.wallet.util.PrefsUtil;
26d19
< import org.apache.commons.lang3.StringUtils;
53,66c46,52
< //public static final String SAMOURAI_API = "https://api.samouraiwallet.com/";
< //public static final String SAMOURAI_API_CHECK = "https://api.samourai.com/v1/status";
< //public static final String SAMOURAI_API2 = "https://api.samouraiwallet.com/v2/";
< //public static final String SAMOURAI_API2_TESTNET = "https://api.samouraiwallet.com/test/v2/";
<
< //public static final String SAMOURAI_API2_TOR_DIST = "http://d2oagweysnavqgcfsfawqwql2rwxend7xxpriq676lzsmtfwbt75qbqd.onion/v2/";
< //public static final String SAMOURAI_API2_TESTNET_TOR_DIST = "http://d2oagweysnavqgcfsfawqwql2rwxend7xxpriq676lzsmtfwbt75qbqd.onion/test/v2/";
<
< public static final String SAMOURAI_API = null;
< public static final String SAMOURAI_API_CHECK = null;
< public static final String SAMOURAI_API2 = null;
< public static final String SAMOURAI_API2_TESTNET = null;
< public static final String SAMOURAI_API2_TESTNET_TOR_DIST = null;
< public static final String SAMOURAI_API2_TOR_DIST = null;
---
> public static final String SAMOURAI_API = "https://api.samouraiwallet.com/";
> public static final String SAMOURAI_API_CHECK = "https://api.samourai.com/v1/status";
> public static final String SAMOURAI_API2 = "https://api.samouraiwallet.com/v2/";
> public static final String SAMOURAI_API2_TESTNET = "https://api.samouraiwallet.com/test/v2/";
>
> public static final String SAMOURAI_API2_TOR_DIST = "http://d2oagweysnavqgcfsfawqwql2rwxend7xxpriq676lzsmtfwbt75qbqd.onion/v2/";
> public static final String SAMOURAI_API2_TESTNET_TOR_DIST = "http://d2oagweysnavqgcfsfawqwql2rwxend7xxpriq676lzsmtfwbt75qbqd.onion/test/v2/";
98,102c84,96
< if (SamouraiTorManager.INSTANCE.isRequired()) {
< if (urlParameters.startsWith("tx=")) {
< HashMap<String, String> args = new HashMap<String, String>();
< args.put("tx", urlParameters.substring(3));
< return tor_postURL(request, args, headers);
---
>
> if (context == null) {
> return postURL(null, request, urlParameters, headers);
> } else {
> // Log.v("WebUtil", "Tor required status:" + SamouraiTorManager.INSTANCE.isRequired());
> if (SamouraiTorManager.INSTANCE.isRequired()) {
> if (urlParameters.startsWith("tx=")) {
> HashMap<String, String> args = new HashMap<String, String>();
> args.put("tx", urlParameters.substring(3));
> return tor_postURL(request, args, headers);
> } else {
> return tor_postURL(request + urlParameters, new HashMap(), headers);
> }
104c98
< return tor_postURL(request + urlParameters, new HashMap(), headers);
---
> return postURL(null, request, urlParameters, headers);
106,107c100
< } else {
< return postURL(null, request, urlParameters, headers);
---
>
108a102
>
111c105
< private String postURL(String contentType, String request, String urlParameters) throws Exception {
---
> public String postURL(String contentType, String request, String urlParameters) throws Exception {
115c109
< private String postURL(String contentType, String request, String urlParameters, Map<String, String> headers) throws HttpException {
---
> public String postURL(String contentType, String request, String urlParameters, Map<String, String> headers) throws HttpException {
187c181
< private String deleteURL(String request, String urlParameters) throws Exception {
---
> public String deleteURL(String request, String urlParameters) throws Exception {
252,261d245
< final Map<String, String> headers = enrichHeaders(inputHeaders);
< if (SamouraiTorManager.INSTANCE.isRequired()) {
< return tor_getURL(url, headers, timeout);
< } else {
< return _getURL(url, headers, timeout);
< }
< }
<
< @NonNull
< private static Map<String, String> enrichHeaders(Map<String, String> inputHeaders) {
269c253,264
< return headers;
---
>
> if (context == null) {
> return _getURL(url, headers, timeout);
> } else {
> //if(TorUtil.getInstance(context).orbotIsRunning()) {
> //Log.v("WebUtil", "Tor required status:" + SamouraiTorManager.INSTANCE.isRequired());
> if (SamouraiTorManager.INSTANCE.isRequired()) {
> return tor_getURL(url, headers, timeout);
> } else {
> return _getURL(url, headers, timeout);
> }
> }
327,334c322
< public String tor_getURL(
< final String url,
< Map<String,String> headers
< ) throws HttpException {
< return tor_getURL(url, headers, DefaultRequestTimeout);
< }
<
< public String tor_getURL(
---
> private String tor_getURL(
336c324
< Map<String,String> inputHeaders,
---
> Map<String,String> headers,
345,346c333,336
< final Map<String, String> headers = enrichHeaders(inputHeaders);
<
---
> // set headers
> if (headers == null) {
> headers = new HashMap<>();
> }
373c363
< if (args != null && !args.isEmpty()) {
---
> if (args != null && args.size()!=0) {
375,376c365
< if (key == null) continue;
< formBodyBuilder.add(key, StringUtils.defaultIfBlank(args.get(key), EMPTY));
---
> formBodyBuilder.add(key, args.get(key));
425d413
< debug("WebUtil", "HttpException: : " + URL + "=>" + e.getMessage());
428d415
< debug("WebUtil", "Exception: : " + URL + "=>" + e.getMessage());
510a498,505
> }
>
> public static String getAPIUrl(Context context) {
> if(SamouraiTorManager.INSTANCE.isRequired()) {
> return SamouraiWallet.getInstance().isTestNet() ? SAMOURAI_API2_TESTNET_TOR : SAMOURAI_API2_TOR;
> } else {
> return SamouraiWallet.getInstance().isTestNet() ? SAMOURAI_API2_TESTNET : SAMOURAI_API2;
> }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/PrefsUtil.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/PrefsUtil.java
20c20
< public static final String WALLET_SCAN_COMPLETE = "wallet_scan_complete";
---
> public static final String FIRST_RUN = "1stRun";
42,44d41
< public static final String XPUBSWAPDEPOLOCK = "xpubswapsdepolock";
< public static final String XPUBSWAPREFUNDSLOCK = "xpubswapsrefundslock";
< public static final String XPUBSWAPASBLOCK = "xpubswapsasblock";
65,66d61
< public static final String BLOCK_EXPLORER_URL = "block_explorer_url";
< public static final String DOJO_NAME = "dojo_name";
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/tech/AppUtil.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/tech/AppUtil.java
9d8
< import android.content.pm.ApplicationInfo;
14,15d12
< import androidx.appcompat.app.AppCompatActivity;
< import androidx.fragment.app.FragmentActivity;
20d16
< import com.samourai.wallet.SamouraiActivity;
33d28
< import com.samourai.wallet.util.Util;
42d36
< import java.io.FileInputStream;
50,51d43
< public static final String TAG = "AppUtil";
<
74d65
< private static MutableLiveData<Boolean> hasUpdateBeenShown = new MutableLiveData<>(false);
121,128d111
< public MutableLiveData<Boolean> getHasUpdateBeenShown() {
< return hasUpdateBeenShown;
< }
<
< public void setHasUpdateBeenShown(boolean beenShown) {
< hasUpdateBeenShown.postValue(beenShown);
< }
<
217,218c200,207
< public void restartAppFromActivity(final Bundle extras, final FragmentActivity fromActivity) {
< final Intent intent = new Intent(fromActivity, MainActivity2.class);
---
> public void restartApp(Bundle extras) {
>
> Intent intent = new Intent(context, MainActivity2.class);
> if (PrefsUtil.getInstance(context).getValue(PrefsUtil.ICON_HIDDEN, false) == true) {
> // intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_SINGLE_TOP);
> } else {
> // intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
> }
222c211,237
< fromActivity.startActivity(intent);
---
> context.startActivity(intent);
> }
>
> public void restartApp(String name, boolean value) {
> Intent intent = new Intent(context, MainActivity2.class);
> if (PrefsUtil.getInstance(context).getValue(PrefsUtil.ICON_HIDDEN, false) == true) {
> intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_SINGLE_TOP);
> } else {
> intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
> }
> if (name != null) {
> intent.putExtra(name, value);
> }
> context.startActivity(intent);
> }
>
> public void restartApp(String name, String value) {
> Intent intent = new Intent(context, MainActivity2.class);
> if (PrefsUtil.getInstance(context).getValue(PrefsUtil.ICON_HIDDEN, false) == true) {
> intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_SINGLE_TOP);
> } else {
> intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
> }
> if (name != null && value != null) {
> intent.putExtra(name, value);
> }
> context.startActivity(intent);
323,336d337
< }
<
< public String getApkSha256() {
< final ApplicationInfo appInfo = context.getApplicationContext().getApplicationInfo();
< final String apkPath = appInfo.sourceDir;
< final File file = new File(apkPath);
< try (final FileInputStream fis = new FileInputStream(file)) {
< byte[] fileBytes = new byte[(int) file.length()];
< fis.read(fileBytes);
< return Util.sha256ToString(fileBytes);
< } catch (final Exception e) {
< Log.e(TAG, "cannot getApkSha256()", e);
< return null;
< }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/tech/HapticHelper.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/tech/HapticHelper.kt
13,15d12
< val hapticTadaPattern = longArrayOf(50L, 64L, 120L, 64L)
< val hapticDaDuration = 60L
<
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/tech/SimpleTaskRunner.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/tech/SimpleTaskRunner.java
13c13
< private static final String TAG = SimpleTaskRunner.class.getSimpleName();
---
> public static final String TAG = SimpleTaskRunner.class.getSimpleName();
23,29d22
< public void executeAsyncAndShutdown(final Runnable runnable) {
< executor.execute(() -> {
< runnable.run();
< shutdown();
< });
< }
<
34,45c27
< public <T> void executeAsync(
< final Callable<T> callable,
< final SimpleCallback<T> simpleCallback) {
<
< executeAsync(false, callable, simpleCallback);
< }
<
< public <T> void executeAsync(
< final boolean shutdownAfterComplete,
< final Callable<T> callable,
< final SimpleCallback<T> simpleCallback) {
<
---
> public <T> void executeAsync(final Callable<T> callable, final SimpleCallback<T> simpleCallback) {
58,60d39
< if (shutdownAfterComplete) {
< shutdown();
< }
63,66d41
< }
<
< public void shutdown() {
< executor.shutdown();
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/tech/ThreadHelper.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/tech/ThreadHelper.java
19,29d18
<
< public static boolean pauseMillisWithStatus(final long pause) {
< try {
< Thread.sleep(pause);
< return true;
< } catch (final InterruptedException e) {
< Thread.currentThread().interrupt();
< Log.e(TAG, "InterruptedException on #pauseMillis", e);
< }
< return false;
< }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/util/view/SamCheckbox.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/util/view/SamCheckbox.kt
35,36c35
< rectColor: Color = Color.White,
< rectColorUnchecked: Color = Color.Transparent
---
> rectColor: Color = Color.White
49c48
< color = if (checked) rectColor else rectColorUnchecked,
---
> color = rectColor,
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/utxos/UTXODetailsActivity.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/utxos/UTXODetailsActivity.java
40d39
< import com.samourai.wallet.util.PrefsUtil;
54d52
< import org.apache.commons.lang3.StringUtils;
239,245c237
< if (!StringUtils.equals(BIP47Meta.getInstance().getName(pcode), BIP47Meta.getInstance().getDisplayLabel(pcode))) {
< ((TextView) paynymLayout.findViewById(R.id.paynym_label)).setText(BIP47Meta.getInstance().getDisplayLabel(pcode));
< ((TextView) paynymLayout.findViewById(R.id.paynym_code)).setText(BIP47Meta.getInstance().getName(pcode));
< } else {
< ((TextView) paynymLayout.findViewById(R.id.paynym_code)).setText(BIP47Meta.getInstance().getName(pcode));
< ((TextView) paynymLayout.findViewById(R.id.paynym_label)).setText("");
< }
---
> ((TextView) paynymLayout.findViewById(R.id.paynym_code)).setText(BIP47Meta.getInstance().getDisplayLabel(pcode));
252d243
< ((TextView) paynymLayout.findViewById(R.id.paynym_label)).setText("");
385,388d375
< if (PrefsUtil.getInstance(getApplicationContext()).getValue(PrefsUtil.BLOCK_EXPLORER_URL, "").isEmpty()) {
< menu.findItem(R.id.utxo_details_view_in_explorer).setVisible(false);
< }
<
406c393
< /*
---
>
411d397
< */
631c617
< SamouraiTorManager.INSTANCE.newIdentity();
---
> SamouraiTorManager.newIdentity();
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/utxos/UTXOSActivity.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/utxos/UTXOSActivity.java
11d10
< import android.util.Log;
59,61d57
< import com.samourai.wallet.util.tech.SimpleCallback;
< import com.samourai.wallet.util.tech.SimpleTaskRunner;
< import com.samourai.wallet.util.tech.ThreadHelper;
65a62
> import com.samourai.wallet.whirlpool.fragments.WhirlPoolLoaderDialog;
66a64
> import com.samourai.whirlpool.client.wallet.AndroidWhirlpoolWalletService;
85d82
< import java.util.concurrent.Callable;
134d130
<
177c173
< AppUtil.getInstance(getApplicationContext()).getWalletLoading().observe(this, aBoolean -> {
---
> AppUtil.getInstance(getApplicationContext()).getWalletLoading().observe(this,aBoolean -> {
179,194c175,176
< if(!aBoolean) {
< SimpleTaskRunner.create().executeAsync(
< true,
< new Callable<Void>() {
< @Override
< public Void call() throws Exception {
< ThreadHelper.pauseMillis(50L);
< return null;
< }
< }, new SimpleCallback<Void>() {
< @Override
< public void onComplete(Void result) {
< // ensore to call in main thread
< loadUTXOs(false);
< }
< });
---
> if(!aBoolean){
> loadUTXOs(false);
269d250
<
271,291c252,253
< SimpleTaskRunner.create().executeAsync(
< true,
< new Callable<List<UTXOCoin>>() {
< @Override
< public List<UTXOCoin> call() throws Exception {
< return applyFilters();
< }
< },
< new SimpleCallback<List<UTXOCoin>>() {
< @Override
< public void onComplete(List<UTXOCoin> result) {
< adapter.updateList(result);
< adapter.notifyDataSetChanged();
< }
<
< @Override
< public void onException(Throwable t) {
< Log.e(TAG, "issue on applyFilters()", t);
< }
< }
< );
---
> applyFilters();
> adapter.notifyDataSetChanged();
296,297c258,259
< @NonNull
< private List<UTXOCoin> applyFilters() {
---
> private void applyFilters() {
>
299c261
< final List<UTXOCoin> filteredStatus = new ArrayList<>();
---
> ArrayList<UTXOCoin> filteredStatus = new ArrayList<>();
366c328
< final List<UTXOCoin> sectioned = new ArrayList<>();
---
> List<UTXOCoin> sectioned = new ArrayList<>();
395c357,358
< return sectioned;
---
>
> this.adapter.updateList(sectioned);
425,432c388
< synchronized private void loadUTXOs(boolean loadSilently) {
<
< if (loadSilently) {
< Log.i(TAG, "will start loading utxo silently");
< } else {
< Log.i(TAG, "will start loading utxo");
< }
<
---
> private void loadUTXOs(boolean loadSilently) {
443,489c399,422
<
< SimpleTaskRunner.create().executeAsync(
< true,
< new Callable<List<UTXOCoin>>() {
< @Override
< synchronized public List<UTXOCoin> call() throws Exception {
< final Map<String, Object> data = getUTXOs();
<
< try {
< totalP2WPKH = (long) data.get("totalP2WPKH");
< totalBlocked = (long) data.get("totalBlocked");
< totalP2SH_P2WPKH = (long) data.get("totalP2SH_P2WPKH");
< totalP2PKH = (long) data.get("totalP2PKH");
< } catch (final Exception e) {
< Log.e(TAG, "issue on get long from stats map", e);
< }
<
< unFilteredUTXOS = new ArrayList<>((List<UTXOCoin>) data.get("utxos"));
< LogUtil.info(TAG, "loadUTXOs: ".concat(String.valueOf(unFilteredUTXOS.size())));
< return applyFilters();
< }
< },
< new SimpleCallback<List<UTXOCoin>>() {
< @Override
< synchronized public void onComplete(final List<UTXOCoin> utxoRowsToDisplay) {
< adapter.updateList(utxoRowsToDisplay);
< if (!loadSilently) {
< utxoProgressBar.setVisibility(View.GONE);
< }
< if (loadSilently) {
< Log.i(TAG, "loading utxo silently is done");
< } else {
< Log.i(TAG, "loading utxo is done");
< }
< }
<
< @Override
< synchronized public void onException(final Throwable t) {
< if (loadSilently) {
< Log.i(TAG, "loading utxo silently is failed", t);
< } else {
< Log.i(TAG, "loading utxo is failed", t);
< }
< if (!loadSilently) {
< utxoSwipeRefresh.setRefreshing(false);
< utxoProgressBar.setVisibility(View.GONE);
< }
---
> Disposable disposable = getUTXOs()
> .subscribeOn(Schedulers.io())
> .observeOn(AndroidSchedulers.mainThread())
> .subscribe(stringObjectMap -> {
> List<UTXOCoin> items = (List<UTXOCoin>) stringObjectMap.get("utxos");
> LogUtil.info(TAG, "loadUTXOs: ".concat(String.valueOf(items.size())));
> try {
> unFilteredUTXOS = new ArrayList<>();
> unFilteredUTXOS.addAll(items);
> applyFilters();
> } catch (Exception ex) {
> ex.printStackTrace();
> }
> totalP2WPKH = (long) stringObjectMap.get("totalP2WPKH");
> totalBlocked = (long) stringObjectMap.get("totalBlocked");
> totalP2SH_P2WPKH = (long) stringObjectMap.get("totalP2SH_P2WPKH");
> totalP2PKH = (long) stringObjectMap.get("totalP2PKH");
> if (!loadSilently) {
> utxoProgressBar.setVisibility(View.GONE);
> }
> }, err -> {
> if (!loadSilently) {
> utxoSwipeRefresh.setRefreshing(false);
> utxoProgressBar.setVisibility(View.GONE);
491,492c424,425
< }
< );
---
> });
> compositeDisposable.add(disposable);
495,509c428,442
< @NonNull
< private Map<String, Object> getUTXOs() {
< long totalP2WPKH = 0L;
< long totalBlocked = 0L;
< long totalP2PKH = 0L;
< long totalP2SH_P2WPKH = 0L;
<
< noteAmounts.clear();
< tagAmounts.clear();
<
< final Map<String, Object> dataSet = new HashMap<>();
< List<UTXO> utxos = null;
< if (account == WhirlpoolMeta.getInstance(getApplicationContext()).getWhirlpoolPostmix()) {
< utxos = APIFactory.getInstance(getApplicationContext()).getUtxosPostMix(false);
< } else {
---
> private Observable<Map<String, Object>> getUTXOs() {
> return Observable.fromCallable(() -> {
> long totalP2WPKH = 0L;
> long totalBlocked = 0L;
> long totalP2PKH = 0L;
> long totalP2SH_P2WPKH = 0L;
>
> noteAmounts.clear();
> tagAmounts.clear();
>
> Map<String, Object> dataSet = new HashMap<>();
> List<UTXO> utxos = null;
> if (account == WhirlpoolMeta.getInstance(getApplicationContext()).getWhirlpoolPostmix()) {
> utxos = APIFactory.getInstance(getApplicationContext()).getUtxosPostMix(false);
> } else {
511,512c444,445
< utxos = APIFactory.getInstance(getApplicationContext()).getUtxos(false);
< }
---
> utxos = APIFactory.getInstance(getApplicationContext()).getUtxos(false);
> }
514,519c447,453
< long amount = 0L;
< for (UTXO utxo : utxos) {
< for (MyTransactionOutPoint out : utxo.getOutpoints()) {
< debug("UTXOSActivity", "utxo:" + out.getAddress() + "," + out.getValue());
< debug("UTXOSActivity", "utxo:" + utxo.getPath());
< amount += out.getValue().longValue();
---
> long amount = 0L;
> for (UTXO utxo : utxos) {
> for (MyTransactionOutPoint out : utxo.getOutpoints()) {
> debug("UTXOSActivity", "utxo:" + out.getAddress() + "," + out.getValue());
> debug("UTXOSActivity", "utxo:" + utxo.getPath());
> amount += out.getValue().longValue();
> }
521d454
< }
523,528c456,461
< ArrayList<UTXOCoin> items = new ArrayList<>();
< for (UTXO utxo : utxos) {
< for (MyTransactionOutPoint outpoint : utxo.getOutpoints()) {
< UTXOCoin displayData = new UTXOCoin(outpoint, utxo);
< if (BlockedUTXO.getInstance().contains(outpoint.getTxHash().toString(), outpoint.getTxOutputN())) {
< totalBlocked += displayData.amount;
---
> ArrayList<UTXOCoin> items = new ArrayList<>();
> for (UTXO utxo : utxos) {
> for (MyTransactionOutPoint outpoint : utxo.getOutpoints()) {
> UTXOCoin displayData = new UTXOCoin(outpoint, utxo);
> if (BlockedUTXO.getInstance().contains(outpoint.getTxHash().toString(), outpoint.getTxOutputN())) {
> totalBlocked += displayData.amount;
530c463
< } else if (BlockedUTXO.getInstance().containsPostMix(outpoint.getTxHash().toString(), outpoint.getTxOutputN())) {
---
> } else if (BlockedUTXO.getInstance().containsPostMix(outpoint.getTxHash().toString(), outpoint.getTxOutputN())) {
532,538c465
< totalBlocked += displayData.amount;
< } else {
< // Log.d("UTXOActivity", "unmarked");
< if (FormatsUtil.getInstance().isValidBech32(displayData.address)) {
< totalP2WPKH += displayData.amount;
< } else if (Address.fromBase58(SamouraiWallet.getInstance().getCurrentNetworkParams(), displayData.address).isP2SHAddress()) {
< totalP2SH_P2WPKH += displayData.amount;
---
> totalBlocked += displayData.amount;
540c467,474
< totalP2PKH += displayData.amount;
---
> // Log.d("UTXOActivity", "unmarked");
> if (FormatsUtil.getInstance().isValidBech32(displayData.address)) {
> totalP2WPKH += displayData.amount;
> } else if (Address.fromBase58(SamouraiWallet.getInstance().getCurrentNetworkParams(), displayData.address).isP2SHAddress()) {
> totalP2SH_P2WPKH += displayData.amount;
> } else {
> totalP2PKH += displayData.amount;
> }
542d475
< }
544,545c477,478
< if (UTXOUtil.getInstance().get(outpoint.getTxHash().toString(), outpoint.getTxOutputN()) != null) {
< List<String> tags = UTXOUtil.getInstance().get(outpoint.getTxHash().toString(), outpoint.getTxOutputN());
---
> if (UTXOUtil.getInstance().get(outpoint.getTxHash().toString(), outpoint.getTxOutputN()) != null) {
> List<String> tags = UTXOUtil.getInstance().get(outpoint.getTxHash().toString(), outpoint.getTxOutputN());
547,553c480,487
< for (String tag : tags) {
< if (tagAmounts.containsKey(tag.toLowerCase())) {
< long val = tagAmounts.get(tag.toLowerCase());
< val += displayData.amount;
< tagAmounts.put(tag.toLowerCase(), val);
< } else {
< tagAmounts.put(tag.toLowerCase(), displayData.amount);
---
> for (String tag : tags) {
> if (tagAmounts.containsKey(tag.toLowerCase())) {
> long val = tagAmounts.get(tag.toLowerCase());
> val += displayData.amount;
> tagAmounts.put(tag.toLowerCase(), val);
> } else {
> tagAmounts.put(tag.toLowerCase(), displayData.amount);
> }
554a489
>
555a491,492
> if (UTXOUtil.getInstance().getNote(outpoint.getTxHash().toString()) != null) {
> String note = UTXOUtil.getInstance().getNote(outpoint.getTxHash().toString());
557,559c494,500
< }
< if (UTXOUtil.getInstance().getNote(outpoint.getTxHash().toString()) != null) {
< String note = UTXOUtil.getInstance().getNote(outpoint.getTxHash().toString());
---
> if (noteAmounts.containsKey(note.toLowerCase())) {
> long val = noteAmounts.get(note.toLowerCase());
> val += displayData.amount;
> noteAmounts.put(note.toLowerCase(), val);
> } else {
> noteAmounts.put(note.toLowerCase(), displayData.amount);
> }
561,566d501
< if (noteAmounts.containsKey(note.toLowerCase())) {
< long val = noteAmounts.get(note.toLowerCase());
< val += displayData.amount;
< noteAmounts.put(note.toLowerCase(), val);
< } else {
< noteAmounts.put(note.toLowerCase(), displayData.amount);
569,574c504,508
< }
<
< boolean exist = false;
< for (int i = 0; i < items.size(); i++) {
< if (items.get(i).hash.equals(displayData.hash) && items.get(i).idx == displayData.idx && items.get(i).path.equals(displayData.path)) {
< exist = true;
---
> boolean exist = false;
> for (int i = 0; i < items.size(); i++) {
> if (items.get(i).hash.equals(displayData.hash) && items.get(i).idx == displayData.idx && items.get(i).path.equals(displayData.path)) {
> exist = true;
> }
576,578c510,513
< }
< if (!exist) {
< items.add(displayData);
---
> if (!exist) {
> items.add(displayData);
> }
>
581a517,521
> dataSet.put("totalP2WPKH", totalP2WPKH);
> dataSet.put("totalBlocked", totalBlocked);
> dataSet.put("totalP2SH_P2WPKH", totalP2SH_P2WPKH);
> dataSet.put("totalP2PKH", totalP2PKH);
> dataSet.put("utxos", items);
583,590c523,524
< }
< dataSet.put("totalP2WPKH", totalP2WPKH);
< dataSet.put("totalBlocked", totalBlocked);
< dataSet.put("totalP2SH_P2WPKH", totalP2SH_P2WPKH);
< dataSet.put("totalP2PKH", totalP2PKH);
< dataSet.put("utxos", items);
<
< return dataSet;
---
> return dataSet;
> });
761d694
< /*
797d729
< */
1096c1028
< holder.rootViewGroup.setBackgroundColor(ContextCompat.getColor(getBaseContext(), R.color.networking));
---
> holder.rootViewGroup.setBackgroundColor(ContextCompat.getColor(getBaseContext(), R.color.windowDark));
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/whirlpool/newPool/fragments/SelectPoolFragment.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/whirlpool/newPool/fragments/SelectPoolFragment.kt
7a8,15
> import androidx.recyclerview.widget.RecyclerView
> import com.samourai.wallet.whirlpool.adapters.PoolsAdapter
> import com.samourai.wallet.whirlpool.models.PoolViewModel
> import com.google.android.material.button.MaterialButton
> import com.samourai.wallet.whirlpool.models.PoolCyclePriority
> import io.reactivex.disposables.CompositeDisposable
> import com.samourai.wallet.whirlpool.newPool.NewPoolViewModel
> import com.samourai.wallet.utxos.models.UTXOCoin
9c17,21
< import android.util.TypedValue
---
> import android.util.Log
> import com.samourai.wallet.R
> import androidx.recyclerview.widget.DefaultItemAnimator
> import androidx.core.content.ContextCompat
> import androidx.recyclerview.widget.LinearLayoutManager
11d22
< import android.view.View
15c26,28
< import androidx.core.content.ContextCompat
---
> import androidx.recyclerview.widget.RecyclerView.ItemDecoration
> import android.util.TypedValue
> import android.view.View
18,23c31
< import androidx.recyclerview.widget.DefaultItemAnimator
< import androidx.recyclerview.widget.LinearLayoutManager
< import androidx.recyclerview.widget.RecyclerView
< import androidx.recyclerview.widget.RecyclerView.ItemDecoration
< import com.google.android.material.button.MaterialButton
< import com.samourai.wallet.R
---
> import com.google.android.material.snackbar.Snackbar
26,31d33
< import com.samourai.wallet.send.FeeUtil
< import com.samourai.wallet.utxos.models.UTXOCoin
< import com.samourai.wallet.whirlpool.adapters.PoolsAdapter
< import com.samourai.wallet.whirlpool.models.PoolCyclePriority
< import com.samourai.wallet.whirlpool.models.PoolViewModel
< import com.samourai.wallet.whirlpool.newPool.NewPoolViewModel
33c35
< import io.reactivex.disposables.CompositeDisposable
---
> import java.util.ArrayList
75,80d76
< }
<
< if (FeeUtil.getInstance().feeRepresentation.is1DolFeeEstimator) {
< binding.feeHighBtn.setText("Next Block")
< } else {
< binding.feeHighBtn.setText("HIGH")
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/whirlpool/WhirlpoolHome.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/whirlpool/WhirlpoolHome.kt
36a37
> import com.samourai.wallet.service.WalletRefreshWorker
39d39
< import com.samourai.wallet.util.func.WalletRefreshUtil
50d49
< import kotlinx.coroutines.async
103,109c102,104
< withContext(Dispatchers.IO) {
< async {
< WalletRefreshUtil.refreshWallet(
< notifTx = false,
< launch = false,
< context = applicationContext)
< }
---
> withContext(Dispatchers.Default){
> delay(800)
> WalletRefreshWorker.enqueue(applicationContext, notifTx = false, launched = false);
252,261c247
< whirlPoolHomeViewModel.viewModelScope.launch {
< withContext(Dispatchers.IO) {
< async {
< WalletRefreshUtil.refreshWallet(
< notifTx = false,
< launch = false,
< context = applicationContext)
< }
< }
< }
---
> WalletRefreshWorker.enqueue(applicationContext, launched = false, notifTx = false)
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/whirlpool/WhirlPoolHomeViewModel.kt /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/whirlpool/WhirlPoolHomeViewModel.kt
16c16
< import com.samourai.wallet.util.func.WalletRefreshUtil
---
> import com.samourai.wallet.service.WalletRefreshWorker
26d25
< import kotlinx.coroutines.async
226,231c225,227
< async(Dispatchers.IO) {
< WalletRefreshUtil.refreshWallet(
< notifTx = false,
< launch = false,
< context = context)
< }.await()
---
> withContext(Dispatchers.Main){
> WalletRefreshWorker.enqueue(context, notifTx = false,launched = false)
> }
234c230
< } catch (e:Exception){
---
> }catch (e:Exception){
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/wallet/widgets/TransactionProgressView.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/wallet/widgets/TransactionProgressView.java
214c214
< optionBtn2.setVisibility(GONE);
---
> optionBtn2.setVisibility(VISIBLE);
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/main/java/com/samourai/whirlpool/client/wallet/data/AndroidMinerFeeSupplier.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/main/java/com/samourai/whirlpool/client/wallet/data/AndroidMinerFeeSupplier.java
3,7d2
< import static java.lang.Math.min;
< import static java.util.Objects.nonNull;
<
< import android.util.Log;
<
9,10d3
< import com.samourai.wallet.api.fee.EnumFeeRate;
< import com.samourai.wallet.api.fee.RawFees;
37,85d29
< feeUtil.normalize();
< switch (feeUtil.getFeeRepresentation()) {
< case NEXT_BLOCK_RATE:
< return getNextBlockFeeRate(feeTarget);
< case BLOCK_COUNT:
< default:
< return getBlockCountFeeRate(feeTarget);
< }
< }
<
< private int getNextBlockFeeRate(final MinerFeeTarget feeTarget) {
<
< final RawFees rawFees = feeUtil.getRawFees();
< BigInteger feePerKB = feeUtil.getNormalFee().getDefaultPerKB();
<
< switch (feeTarget) {
< case BLOCKS_2: case BLOCKS_4:
< feePerKB = feeUtil.getHighFee().getDefaultPerKB();
< break;
<
< case BLOCKS_6:
< feePerKB = feeUtil.getNormalFee().getDefaultPerKB();
< break;
<
< case BLOCKS_12: case BLOCKS_24: {
< final Integer fee100 = rawFees.getFee(EnumFeeRate.RATE_100);
< if (nonNull(fee100)) return fee100;
< final Integer fee990 = rawFees.getFee(EnumFeeRate.RATE_990);
< if (nonNull(fee990)) {
< return min(fee990 / 2, feeUtil.getNormalFee().getDefaultPerKB().intValue() / 1000);
< } else {
< feePerKB = feeUtil.getLowFee().getDefaultPerKB();
< Log.e(
< AndroidMinerFeeSupplier.class.getSimpleName(),
< "inconsistent state : " + EnumFeeRate.RATE_990.getRateAsString() + " is null");
< }
< break;
< }
<
< default:
< log.error("unknown MinerFeeTarget: "+feeTarget);
< break;
< }
< long feePerB = feePerKB.longValue() / 1000L;
< return (int)feePerB;
< }
<
< private int getBlockCountFeeRate(final MinerFeeTarget feeTarget) {
<
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/test/java/com/samourai/whirlpool/client/wallet/AbstractWhirlpoolTest.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/test/java/com/samourai/whirlpool/client/wallet/AbstractWhirlpoolTest.java
60c60
< // init Ashigaru
---
> // init Samourai Wallet
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/app/src/test/java/com/samourai/whirlpool/client/wallet/WhirlpoolWalletTest.java /home/laurent/dev_samourai/samourai-wallet-android/app/src/test/java/com/samourai/whirlpool/client/wallet/WhirlpoolWalletTest.java
15d14
< import com.samourai.wallet.util.network.BackendApiAndroid;
63c62
< BackendApi backendApi = new BackendApi(httpClient, BackendApiAndroid.getApiBaseUrl(), null) {
---
> BackendApi backendApi = new BackendApi(httpClient, BackendServer.TESTNET.getBackendUrl(onion), null) {
122,144c121,142
< /* needs to be upgraded in according to extlibj */
< // @Test
< // public void testTx0() throws Exception {
< // Collection<UnspentOutput> spendFroms = new LinkedList<>();
< // SimpleUtxoKeyProvider utxoKeyProvider = new SimpleUtxoKeyProvider();
< //
< // ECKey ecKey = bip84w.getAccount(0).getChain(0).getAddressAt(61).getECKey();
< // UnspentOutput unspentOutput = newUnspentOutput(
< // "cc588cdcb368f894a41c372d1f905770b61ecb3fb8e5e01a97e7cedbf5e324ae", 1, 500000000);
< // unspentOutput.addr = new SegwitAddress(ecKey, networkParameters).getBech32AsString();
< // spendFroms.add(unspentOutput);
< // utxoKeyProvider.setKey(unspentOutput.computeOutpoint(networkParameters), ecKey);
< //
< // Pool pool = whirlpoolWallet.getPoolSupplier().findPoolById("0.01btc");
< // Tx0Info tx0Info = AsyncUtil.getInstance().blockingGet(whirlpoolWallet.fetchTx0Info());
< // Tx0Config tx0Config = tx0Info.getTx0Config(Tx0FeeTarget.BLOCKS_2, Tx0FeeTarget.BLOCKS_2);
< // Tx0Previews tx0Previews = tx0Info.tx0Previews(tx0Config, spendFroms);
< // Tx0Preview tx0Preview = tx0Previews.getTx0Preview(pool.getPoolId());
< // Tx0 tx0 = tx0Info.tx0(whirlpoolWallet.getWalletSupplier(), whirlpoolWallet.getUtxoSupplier(), spendFroms, tx0Config, pool);
< //
< // Assert.assertEquals("dc398c99cf9ce18123ea916d69bb99da44a3979a625eeaac5e17837f879a8874", tx0.getTx().getHashAsString());
< // Assert.assertEquals("01000000000101ae24e3f5dbcee7971ae0e5b83fcb1eb67057901f2d371ca494f868b3dc8c58cc0100000000ffffffff040000000000000000426a408a9eb379a44ff4d4579118c64b64bbd327cd95ba826ac68f334155fd9ca4e3acd64acdfd75dd7c3cc5bc34d31af6c6e68b4db37eac62b574890f6cfc7b904d9950c300000000000016001441021632871b0f1cf61a7ac7b6a0187e88628291b44b0f00000000001600147e4a4628dd8fbd638681a728e39f7d92ada04070e954bd1d00000000160014df3a4bc83635917ad18621f3ba78cef6469c5f5902483045022100c48f02762ab9877533b5c7b0bc729479ce7809596b89cb9f62b740ea3350068f02205ef46ca67df39d35f940e33223c5ddd56669d953b6ef4948e355c1f3430f32e10121032e46baef8bcde0c3a19cadb378197fa31d69adb21535de3f84de699a1cf88b4500000000", new String(Hex.encode(tx0.getTx().bitcoinSerialize())));
< // }
---
> @Test
> public void testTx0() throws Exception {
> Collection<UnspentOutput> spendFroms = new LinkedList<>();
> SimpleUtxoKeyProvider utxoKeyProvider = new SimpleUtxoKeyProvider();
>
> ECKey ecKey = bip84w.getAccount(0).getChain(0).getAddressAt(61).getECKey();
> UnspentOutput unspentOutput = newUnspentOutput(
> "cc588cdcb368f894a41c372d1f905770b61ecb3fb8e5e01a97e7cedbf5e324ae", 1, 500000000);
> unspentOutput.addr = new SegwitAddress(ecKey, networkParameters).getBech32AsString();
> spendFroms.add(unspentOutput);
> utxoKeyProvider.setKey(unspentOutput.computeOutpoint(networkParameters), ecKey);
>
> Pool pool = whirlpoolWallet.getPoolSupplier().findPoolById("0.01btc");
> Tx0Info tx0Info = AsyncUtil.getInstance().blockingGet(whirlpoolWallet.fetchTx0Info());
> Tx0Config tx0Config = tx0Info.getTx0Config(Tx0FeeTarget.BLOCKS_2, Tx0FeeTarget.BLOCKS_2);
> Tx0Previews tx0Previews = tx0Info.tx0Previews(tx0Config, spendFroms);
> Tx0Preview tx0Preview = tx0Previews.getTx0Preview(pool.getPoolId());
> Tx0 tx0 = tx0Info.tx0(whirlpoolWallet.getWalletSupplier(), whirlpoolWallet.getUtxoSupplier(), spendFroms, tx0Config, pool);
>
> Assert.assertEquals("dc398c99cf9ce18123ea916d69bb99da44a3979a625eeaac5e17837f879a8874", tx0.getTx().getHashAsString());
> Assert.assertEquals("01000000000101ae24e3f5dbcee7971ae0e5b83fcb1eb67057901f2d371ca494f868b3dc8c58cc0100000000ffffffff040000000000000000426a408a9eb379a44ff4d4579118c64b64bbd327cd95ba826ac68f334155fd9ca4e3acd64acdfd75dd7c3cc5bc34d31af6c6e68b4db37eac62b574890f6cfc7b904d9950c300000000000016001441021632871b0f1cf61a7ac7b6a0187e88628291b44b0f00000000001600147e4a4628dd8fbd638681a728e39f7d92ada04070e954bd1d00000000160014df3a4bc83635917ad18621f3ba78cef6469c5f5902483045022100c48f02762ab9877533b5c7b0bc729479ce7809596b89cb9f62b740ea3350068f02205ef46ca67df39d35f940e33223c5ddd56669d953b6ef4948e355c1f3430f32e10121032e46baef8bcde0c3a19cadb378197fa31d69adb21535de3f84de699a1cf88b4500000000", new String(Hex.encode(tx0.getTx().bitcoinSerialize())));
> }
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/gradlew /home/laurent/dev_samourai/samourai-wallet-android/gradlew
1,17c1
< #!/bin/sh
<
< #
< # Copyright © 2015-2021 the original authors.
< #
< # Licensed under the Apache License, Version 2.0 (the "License");
< # you may not use this file except in compliance with the License.
< # You may obtain a copy of the License at
< #
< # https://www.apache.org/licenses/LICENSE-2.0
< #
< # Unless required by applicable law or agreed to in writing, software
< # distributed under the License is distributed on an "AS IS" BASIS,
< # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
< # See the License for the specific language governing permissions and
< # limitations under the License.
< #
---
> #!/usr/bin/env bash
20,62c4,6
< #
< # Gradle start up script for POSIX generated by Gradle.
< #
< # Important for running:
< #
< # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
< # noncompliant, but you have some other compliant shell such as ksh or
< # bash, then to run this script, type that shell name before the whole
< # command line, like:
< #
< # ksh Gradle
< #
< # Busybox and similar reduced shells will NOT work, because this script
< # requires all of these POSIX shell features:
< # * functions;
< # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
< # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
< # * compound commands having a testable exit status, especially «case»;
< # * various built-in commands including «command», «set», and «ulimit».
< #
< # Important for patching:
< #
< # (2) This script targets any POSIX shell, so it avoids extensions provided
< # by Bash, Ksh, etc; in particular arrays are avoided.
< #
< # The "traditional" practice of packing multiple parameters into a
< # space-separated string is a well documented source of bugs and security
< # problems, so this is (mostly) avoided, by progressively accumulating
< # options in "$@", and eventually passing that to Java.
< #
< # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
< # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
< # see the in-line comments for details.
< #
< # There are tweaks for specific operating systems such as AIX, CygWin,
< # Darwin, MinGW, and NonStop.
< #
< # (3) This script is generated from the Groovy template
< # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
< # within the Gradle project.
< #
< # You can find Gradle at https://github.com/gradle/gradle/.
< #
---
> ##
> ## Gradle start up script for UN*X
> ##
65,81c9,10
< # Attempt to set APP_HOME
<
< # Resolve links: $0 may be a link
< app_path=$0
<
< # Need this for daisy-chained symlinks.
< while
< APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
< [ -h "$app_path" ]
< do
< ls=$( ls -ld "$app_path" )
< link=${ls#*' -> '}
< case $link in #(
< /*) app_path=$link ;; #(
< *) app_path=$APP_HOME$link ;;
< esac
< done
---
> # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
> DEFAULT_JVM_OPTS=""
83,87c12,13
< # This is normally unused
< # shellcheck disable=SC2034
< APP_BASE_NAME=${0##*/}
< # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
< APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
---
> APP_NAME="Gradle"
> APP_BASE_NAME=`basename "$0"`
90c16
< MAX_FD=maximum
---
> MAX_FD="maximum"
92c18
< warn () {
---
> warn ( ) {
94c20
< } >&2
---
> }
96c22
< die () {
---
> die ( ) {
101c27
< } >&2
---
> }
107,112c33,42
< nonstop=false
< case "$( uname )" in #(
< CYGWIN* ) cygwin=true ;; #(
< Darwin* ) darwin=true ;; #(
< MSYS* | MINGW* ) msys=true ;; #(
< NONSTOP* ) nonstop=true ;;
---
> case "`uname`" in
> CYGWIN* )
> cygwin=true
> ;;
> Darwin* )
> darwin=true
> ;;
> MINGW* )
> msys=true
> ;;
115c45,61
< CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
---
> # Attempt to set APP_HOME
> # Resolve links: $0 may be a link
> PRG="$0"
> # Need this for relative symlinks.
> while [ -h "$PRG" ] ; do
> ls=`ls -ld "$PRG"`
> link=`expr "$ls" : '.*-> \(.*\)$'`
> if expr "$link" : '/.*' > /dev/null; then
> PRG="$link"
> else
> PRG=`dirname "$PRG"`"/$link"
> fi
> done
> SAVED="`pwd`"
> cd "`dirname \"$PRG\"`/" >/dev/null
> APP_HOME="`pwd -P`"
> cd "$SAVED" >/dev/null
116a63
> CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
122c69
< JAVACMD=$JAVA_HOME/jre/sh/java
---
> JAVACMD="$JAVA_HOME/jre/sh/java"
124c71
< JAVACMD=$JAVA_HOME/bin/java
---
> JAVACMD="$JAVA_HOME/bin/java"
133,136c80,81
< JAVACMD=java
< if ! command -v java >/dev/null 2>&1
< then
< die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
---
> JAVACMD="java"
> which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
140d84
< fi
144,159c88,100
< if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
< case $MAX_FD in #(
< max*)
< # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
< # shellcheck disable=SC2039,SC3045
< MAX_FD=$( ulimit -H -n ) ||
< warn "Could not query maximum file descriptor limit"
< esac
< case $MAX_FD in #(
< '' | soft) :;; #(
< *)
< # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
< # shellcheck disable=SC2039,SC3045
< ulimit -n "$MAX_FD" ||
< warn "Could not set maximum file descriptor limit to $MAX_FD"
< esac
---
> if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
> MAX_FD_LIMIT=`ulimit -H -n`
> if [ $? -eq 0 ] ; then
> if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
> MAX_FD="$MAX_FD_LIMIT"
> fi
> ulimit -n $MAX_FD
> if [ $? -ne 0 ] ; then
> warn "Could not set maximum file descriptor limit: $MAX_FD"
> fi
> else
> warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
> fi
162,175c103,106
< # Collect all arguments for the java command, stacking in reverse order:
< # * args from the command line
< # * the main class name
< # * -classpath
< # * -D...appname settings
< # * --module-path (only if needed)
< # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
<
< # For Cygwin or MSYS, switch paths to Windows format before running java
< if "$cygwin" || "$msys" ; then
< APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
< CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
<
< JAVACMD=$( cygpath --unix "$JAVACMD" )
---
> # For Darwin, add options to specify how the application appears in the dock
> if $darwin; then
> GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
> fi
176a108,125
> # For Cygwin, switch paths to Windows format before running java
> if $cygwin ; then
> APP_HOME=`cygpath --path --mixed "$APP_HOME"`
> CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
> JAVACMD=`cygpath --unix "$JAVACMD"`
>
> # We build the pattern for arguments to be converted via cygpath
> ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
> SEP=""
> for dir in $ROOTDIRSRAW ; do
> ROOTDIRS="$ROOTDIRS$SEP$dir"
> SEP="|"
> done
> OURCYGPATTERN="(^($ROOTDIRS))"
> # Add a user-defined pattern to the cygpath arguments
> if [ "$GRADLE_CYGPATTERN" != "" ] ; then
> OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
> fi
178,187c127,135
< for arg do
< if
< case $arg in #(
< -*) false ;; # don't mess with options #(
< /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
< [ -e "$t" ] ;; #(
< *) false ;;
< esac
< then
< arg=$( cygpath --path --ignore --mixed "$arg" )
---
> i=0
> for arg in "$@" ; do
> CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
> CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
>
> if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
> eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
> else
> eval `echo args$i`="\"$arg\""
189,197c137
< # Roll the args list around exactly as many times as the number of
< # args, so each arg winds up back in the position where it started, but
< # possibly modified.
< #
< # NB: a `for` loop captures its iteration list before it begins, so
< # changing the positional parameters here affects neither the number of
< # iterations, nor the values presented in `arg`.
< shift # remove old arg
< set -- "$@" "$arg" # push replacement arg
---
> i=$((i+1))
198a139,150
> case $i in
> (0) set -- ;;
> (1) set -- "$args0" ;;
> (2) set -- "$args0" "$args1" ;;
> (3) set -- "$args0" "$args1" "$args2" ;;
> (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
> (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
> (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
> (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
> (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
> (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
> esac
200a153,158
> # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
> function splitJvmOpts() {
> JVM_OPTS=("$@")
> }
> eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
> JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
202,249c160
< # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
< DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
<
< # Collect all arguments for the java command:
< # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
< # and any embedded shellness will be escaped.
< # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
< # treated as '${Hostname}' itself on the command line.
<
< set -- \
< "-Dorg.gradle.appname=$APP_BASE_NAME" \
< -classpath "$CLASSPATH" \
< org.gradle.wrapper.GradleWrapperMain \
< "$@"
<
< # Stop when "xargs" is not available.
< if ! command -v xargs >/dev/null 2>&1
< then
< die "xargs is not available"
< fi
<
< # Use "xargs" to parse quoted args.
< #
< # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
< #
< # In Bash we could simply go:
< #
< # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
< # set -- "${ARGS[@]}" "$@"
< #
< # but POSIX shell has neither arrays nor command substitution, so instead we
< # post-process each arg (as a line of input to sed) to backslash-escape any
< # character that might be a shell metacharacter, then use eval to reverse
< # that process (while maintaining the separation between arguments), and wrap
< # the whole thing up as a single "set" statement.
< #
< # This will of course break if any of these variables contains a newline or
< # an unmatched quote.
< #
<
< eval "set -- $(
< printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
< xargs -n1 |
< sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
< tr '\n' ' '
< )" '"$@"'
<
< exec "$JAVACMD" "$@"
---
> exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/gradlew.bat /home/laurent/dev_samourai/samourai-wallet-android/gradlew.bat
1,17c1
< @rem
< @rem Copyright 2015 the original author or authors.
< @rem
< @rem Licensed under the Apache License, Version 2.0 (the "License");
< @rem you may not use this file except in compliance with the License.
< @rem You may obtain a copy of the License at
< @rem
< @rem https://www.apache.org/licenses/LICENSE-2.0
< @rem
< @rem Unless required by applicable law or agreed to in writing, software
< @rem distributed under the License is distributed on an "AS IS" BASIS,
< @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
< @rem See the License for the specific language governing permissions and
< @rem limitations under the License.
< @rem
<
< @if "%DEBUG%"=="" @echo off
---
> @if "%DEBUG%" == "" @echo off
26a11,13
> @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
> set DEFAULT_JVM_OPTS=
>
28,29c15
< if "%DIRNAME%"=="" set DIRNAME=.
< @rem This is normally unused
---
> if "%DIRNAME%" == "" set DIRNAME=.
33,38d18
< @rem Resolve any "." and ".." in APP_HOME to make it shorter.
< for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
<
< @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
< set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
<
44c24
< if %ERRORLEVEL% equ 0 goto execute
---
> if "%ERRORLEVEL%" == "0" goto init
46,50c26,30
< echo. 1>&2
< echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
< echo. 1>&2
< echo Please set the JAVA_HOME variable in your environment to match the 1>&2
< echo location of your Java installation. 1>&2
---
> echo.
> echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
> echo.
> echo Please set the JAVA_HOME variable in your environment to match the
> echo location of your Java installation.
58c38
< if exist "%JAVA_EXE%" goto execute
---
> if exist "%JAVA_EXE%" goto init
60,64c40,44
< echo. 1>&2
< echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
< echo. 1>&2
< echo Please set the JAVA_HOME variable in your environment to match the 1>&2
< echo location of your Java installation. 1>&2
---
> echo.
> echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
> echo.
> echo Please set the JAVA_HOME variable in your environment to match the
> echo location of your Java installation.
67a48,68
> :init
> @rem Get command-line arguments, handling Windowz variants
>
> if not "%OS%" == "Windows_NT" goto win9xME_args
> if "%@eval[2+2]" == "4" goto 4NT_args
>
> :win9xME_args
> @rem Slurp the command line arguments.
> set CMD_LINE_ARGS=
> set _SKIP=2
>
> :win9xME_args_slurp
> if "x%~1" == "x" goto execute
>
> set CMD_LINE_ARGS=%*
> goto execute
>
> :4NT_args
> @rem Get arguments from the 4NT Shell from JP Software
> set CMD_LINE_ARGS=%$
>
73d73
<
75c75
< "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
---
> "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
79c79
< if %ERRORLEVEL% equ 0 goto mainEnd
---
> if "%ERRORLEVEL%"=="0" goto mainEnd
84,87c84,85
< set EXIT_CODE=%ERRORLEVEL%
< if %EXIT_CODE% equ 0 set EXIT_CODE=1
< if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
< exit /b %EXIT_CODE%
---
> if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
> exit /b 1
$ diff /home/laurent/dev/ashigaru_commit2/ashigaru-mobile/settings.gradle /home/laurent/dev_samourai/samourai-wallet-android/settings.gradle
3,4d2
<
< include ':ExtLibJ'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment