From 5af70848a7b9320560ca6db873ce05f4fad3c4d5 Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Thu, 7 Apr 2016 01:45:48 +0200 Subject: [PATCH] Move password check at startup before init rest of app. cleanup, wording improvements --- .../java/io/bitsquare/btc/WalletService.java | 5 -- .../java/io/bitsquare/trade/offer/Offer.java | 6 +-- .../java/io/bitsquare/app/BitsquareApp.java | 2 +- .../io/bitsquare/gui/main/MainViewModel.java | 36 +++++++++++---- .../content/password/PasswordView.java | 2 +- .../content/seedwords/SeedWordsView.java | 1 + .../gui/main/funds/locked/LockedView.java | 14 +----- .../gui/main/funds/reserved/ReservedView.java | 14 +----- .../offer/createoffer/CreateOfferView.java | 33 ++++++++----- .../main/offer/takeoffer/TakeOfferView.java | 30 +++++++----- .../bitsquare/gui/main/overlays/Overlay.java | 11 ++++- .../overlays/windows/OfferDetailsWindow.java | 6 +-- .../windows/WalletPasswordWindow.java | 6 ++- .../pendingtrades/PendingTradesDataModel.java | 46 ++++++++----------- .../steps/buyer/BuyerStep5View.java | 40 +++++++++++----- .../resources/i18n/displayStrings.properties | 4 +- 16 files changed, 142 insertions(+), 114 deletions(-) diff --git a/core/src/main/java/io/bitsquare/btc/WalletService.java b/core/src/main/java/io/bitsquare/btc/WalletService.java index bee8ad32d7..8eb1bfe097 100644 --- a/core/src/main/java/io/bitsquare/btc/WalletService.java +++ b/core/src/main/java/io/bitsquare/btc/WalletService.java @@ -383,11 +383,6 @@ public class WalletService { return ImmutableList.copyOf(addressEntryList); } - public void swapTradeToSavings(String offerId) { - getOrCreateAddressEntry(offerId, AddressEntry.Context.OFFER_FUNDING); - addressEntryList.swapTradeToSavings(offerId); - } - public void swapTradeEntryToAvailableEntry(String offerId, AddressEntry.Context context) { Optional addressEntryOptional = getAddressEntryListAsImmutableList().stream() .filter(e -> offerId.equals(e.getOfferId())) diff --git a/core/src/main/java/io/bitsquare/trade/offer/Offer.java b/core/src/main/java/io/bitsquare/trade/offer/Offer.java index fd883cd8cd..7c4ca84cf6 100644 --- a/core/src/main/java/io/bitsquare/trade/offer/Offer.java +++ b/core/src/main/java/io/bitsquare/trade/offer/Offer.java @@ -58,9 +58,9 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload @JsonExclude private static final Logger log = LoggerFactory.getLogger(Offer.class); public static final long TTL = TimeUnit.SECONDS.toMillis(4 * 60); - public final static String TAC_OFFERER = "With placing that offer I accept to trade " + - "with anyone who fulfills the conditions as defined above."; - public static final String TAC_TAKER = "With taking that offer I commit to the trade conditions as defined above."; + public final static String TAC_OFFERER = "With placing that offer I agree to trade " + + "with any trader who fulfills the conditions as defined above."; + public static final String TAC_TAKER = "With taking that offer I agree to the trade conditions as defined above."; /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java index badde5bcfd..2316d20cdd 100644 --- a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java +++ b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java @@ -76,7 +76,7 @@ import static io.bitsquare.app.BitsquareEnvironment.APP_NAME_KEY; public class BitsquareApp extends Application { private static final Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(BitsquareApp.class); - public static final boolean DEV_MODE = true; + public static final boolean DEV_MODE = false; public static final boolean IS_RELEASE_VERSION = !DEV_MODE && true; private static Environment env; diff --git a/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java index da0f1e052c..4e85b552fa 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java @@ -409,6 +409,26 @@ public class MainViewModel implements ViewModel { } private void onAllServicesInitialized() { + // In case we have any offers open or a pending trade we need to unlock our trading wallet so a trade can be executed automatically + // Otherwise we delay the password request to create offer, or take offer. + // When the password is set it will be stored to the tradeWalletService as well, so its only needed after a restart. + if (walletService.getWallet().isEncrypted() && + (openOfferManager.getOpenOffers().size() > 0 + || tradeManager.getTrades().size() > 0 + || disputeManager.getDisputesAsObservableList().size() > 0)) { + walletPasswordWindow + .onAesKey(aesKey -> { + tradeWalletService.setAesKey(aesKey); + onAllServicesInitializedAndUnlocked(); + }) + .hideCloseButton() + .show(); + } else { + onAllServicesInitializedAndUnlocked(); + } + } + + private void onAllServicesInitializedAndUnlocked() { Log.traceCall(); clock.start(); @@ -435,15 +455,6 @@ public class MainViewModel implements ViewModel { }); // walletService - // In case we have any offers open or a pending trade we need to unlock our trading wallet so a trade can be executed automatically - // Otherwise we delay the password request to create offer, or take offer. - // When the password is set it will be stored to the tradeWalletService as well, so its only needed after a restart. - if (walletService.getWallet().isEncrypted() && - (openOfferManager.getOpenOffers().size() > 0 - || tradeManager.getTrades().size() > 0 - || disputeManager.getDisputesAsObservableList().size() > 0)) { - walletPasswordWindow.onAesKey(aesKey -> tradeWalletService.setAesKey(aesKey)).show(); - } walletService.addBalanceListener(new BalanceListener() { @Override public void onBalanceChanged(Coin balance, Transaction tx) { @@ -463,6 +474,7 @@ public class MainViewModel implements ViewModel { updateBalance(); setupDevDummyPaymentAccount(); setupMarketPriceFeed(); + swapPendingOfferFundingEntries(); showAppScreen.set(true); @@ -677,6 +689,12 @@ public class MainViewModel implements ViewModel { } } + private void swapPendingOfferFundingEntries() { + tradeManager.getAddressEntriesForAvailableBalanceStream() + .filter(addressEntry -> addressEntry.getOfferId() != null) + .forEach(addressEntry -> walletService.swapTradeEntryToAvailableEntry(addressEntry.getOfferId(), AddressEntry.Context.OFFER_FUNDING)); + } + private void updateBalance() { updateAvailableBalance(); updateReservedBalance(); diff --git a/gui/src/main/java/io/bitsquare/gui/main/account/content/password/PasswordView.java b/gui/src/main/java/io/bitsquare/gui/main/account/content/password/PasswordView.java index 31e0a78b93..4fc9cc157c 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/account/content/password/PasswordView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/account/content/password/PasswordView.java @@ -147,7 +147,7 @@ public class PasswordView extends ActivatableView { " withdrawing bitcoin out of your wallet or " + "if you want to view or restore a wallet from seed words.\n" + "For the transactions used in the trade process we don't support password protection as that would make automatic offer " + - "execution impossible.", + "execution impossible, but you need to provide the password at application startup if you have open offer, trades or disputes.", Layout.FIRST_ROW_AND_GROUP_DISTANCE); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/account/content/seedwords/SeedWordsView.java b/gui/src/main/java/io/bitsquare/gui/main/account/content/seedwords/SeedWordsView.java index f0cbc3c669..985dd7ab6e 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/account/content/seedwords/SeedWordsView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/account/content/seedwords/SeedWordsView.java @@ -91,6 +91,7 @@ public class SeedWordsView extends ActivatableView { addTitledGroupBg(root, gridRow, 2, "Backup your wallet seed words"); displaySeedWordsTextArea = addLabelTextArea(root, gridRow, "Wallet seed words:", "", Layout.FIRST_ROW_DISTANCE).second; displaySeedWordsTextArea.setPrefHeight(60); + displaySeedWordsTextArea.setEditable(false); datePicker = addLabelDatePicker(root, ++gridRow, "Creation Date:").second; datePicker.setMouseTransparent(true); diff --git a/gui/src/main/java/io/bitsquare/gui/main/funds/locked/LockedView.java b/gui/src/main/java/io/bitsquare/gui/main/funds/locked/LockedView.java index 376baf8e0a..40cf9feb19 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/funds/locked/LockedView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/funds/locked/LockedView.java @@ -240,19 +240,7 @@ public class LockedView extends ActivatableView { if (item != null && !empty) { Optional tradableOptional = getTradable(item); if (tradableOptional.isPresent()) { - AddressEntry addressEntry = item.getAddressEntry(); - String details; - if (addressEntry.isTrade()) { - details = "Trade ID: " + addressEntry.getShortOfferId(); - } else if (addressEntry.isOpenOffer()) { - details = "Offer ID: " + addressEntry.getShortOfferId(); - } else if (addressEntry.getContext() == AddressEntry.Context.ARBITRATOR) { - details = "Arbitration fee"; - } else { - details = "-"; - } - - field = new HyperlinkWithIcon("Locked in trade with ID: " + details + " (MultiSig)", + field = new HyperlinkWithIcon("Locked in MultiSig for trade with ID: " + item.getAddressEntry().getShortOfferId(), AwesomeIcon.INFO_SIGN); field.setOnAction(event -> openDetailPopup(item)); field.setTooltip(new Tooltip("Open popup for details")); diff --git a/gui/src/main/java/io/bitsquare/gui/main/funds/reserved/ReservedView.java b/gui/src/main/java/io/bitsquare/gui/main/funds/reserved/ReservedView.java index 2b0460b09d..1b33f6e0bf 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/funds/reserved/ReservedView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/funds/reserved/ReservedView.java @@ -240,19 +240,7 @@ public class ReservedView extends ActivatableView { if (item != null && !empty) { Optional tradableOptional = getTradable(item); if (tradableOptional.isPresent()) { - AddressEntry addressEntry = item.getAddressEntry(); - String details; - if (addressEntry.isTrade()) { - details = "Trade ID: " + addressEntry.getShortOfferId(); - } else if (addressEntry.isOpenOffer()) { - details = "Offer ID: " + addressEntry.getShortOfferId(); - } else if (addressEntry.getContext() == AddressEntry.Context.ARBITRATOR) { - details = "Arbitration fee"; - } else { - details = "-"; - } - - field = new HyperlinkWithIcon("Reserved in offer with ID: " + details + " (local wallet)", + field = new HyperlinkWithIcon("Reserved in local wallet for offer with ID: " + item.getAddressEntry().getShortOfferId(), AwesomeIcon.INFO_SIGN); field.setOnAction(event -> openDetailPopup(item)); field.setTooltip(new Tooltip("Open popup for details")); diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java index 1973e303ac..c7919aa279 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java @@ -290,17 +290,28 @@ public class CreateOfferView extends ActivatableViewAndModel { protected final Logger log = LoggerFactory.getLogger(this.getClass()); + /////////////////////////////////////////////////////////////////////////////////////////// // Enum /////////////////////////////////////////////////////////////////////////////////////////// @@ -128,7 +129,8 @@ public abstract class Overlay { protected Timer centerTime; protected double buttonDistance = 20; protected Type type = Type.Undefined; - + protected boolean hideCloseButton; + /////////////////////////////////////////////////////////////////////////////////////////// // Public API @@ -334,6 +336,11 @@ public abstract class Overlay { return (T) this; } + public T hideCloseButton() { + this.hideCloseButton = true; + return (T) this; + } + /////////////////////////////////////////////////////////////////////////////////////////// // Protected @@ -715,7 +722,7 @@ public abstract class Overlay { GridPane.setColumnSpan(hBox, 2); GridPane.setMargin(hBox, new Insets(buttonDistance, 0, 0, 0)); gridPane.getChildren().add(hBox); - } else { + } else if (!hideCloseButton) { closeButton.setDefaultButton(true); GridPane.setHalignment(closeButton, HPos.RIGHT); if (!showReportErrorButtons) diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/OfferDetailsWindow.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/OfferDetailsWindow.java index f8989e1165..7195dffd51 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/OfferDetailsWindow.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/OfferDetailsWindow.java @@ -84,7 +84,7 @@ public class OfferDetailsWindow extends Overlay { this.tradeAmount = tradeAmount; rowIndex = -1; - width = 850; + width = 900; createGridPane(); addContent(); display(); @@ -93,7 +93,7 @@ public class OfferDetailsWindow extends Overlay { public void show(Offer offer) { this.offer = offer; rowIndex = -1; - width = 850; + width = 900; createGridPane(); addContent(); display(); @@ -222,7 +222,7 @@ public class OfferDetailsWindow extends Overlay { if (placeOfferHandlerOptional.isPresent()) { addTitledGroupBg(gridPane, ++rowIndex, 1, "Commitment", Layout.GROUP_DISTANCE); - addLabelTextField(gridPane, rowIndex, "Please note:", Offer.TAC_OFFERER, Layout.FIRST_ROW_AND_GROUP_DISTANCE); + addLabelTextField(gridPane, rowIndex, "I agree:", Offer.TAC_OFFERER, Layout.FIRST_ROW_AND_GROUP_DISTANCE); addConfirmAndCancelButtons(true); } else if (takeOfferHandlerOptional.isPresent()) { diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/WalletPasswordWindow.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/WalletPasswordWindow.java index 963b156842..353fec18c2 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/WalletPasswordWindow.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/WalletPasswordWindow.java @@ -92,7 +92,6 @@ public class WalletPasswordWindow extends Overlay { display(); } - public WalletPasswordWindow onAesKey(AesKeyHandler aesKeyHandler) { this.aesKeyHandler = aesKeyHandler; return this; @@ -137,7 +136,10 @@ public class WalletPasswordWindow extends Overlay { hBox.setSpacing(10); GridPane.setRowIndex(hBox, ++rowIndex); GridPane.setColumnIndex(hBox, 1); - hBox.getChildren().addAll(unlockButton, cancelButton); + if (hideCloseButton) + hBox.getChildren().add(unlockButton); + else + hBox.getChildren().addAll(unlockButton, cancelButton); gridPane.getChildren().add(hBox); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java index 20f8d0d6d9..242bdc7fe1 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java @@ -71,7 +71,7 @@ public class PendingTradesDataModel extends ActivatableDataModel { private final KeyRing keyRing; public final DisputeManager disputeManager; public final Navigation navigation; - private final WalletPasswordWindow walletPasswordWindow; + public final WalletPasswordWindow walletPasswordWindow; private final NotificationCenter notificationCenter; final ObservableList list = FXCollections.observableArrayList(); @@ -147,12 +147,26 @@ public class PendingTradesDataModel extends ActivatableDataModel { ((SellerTrade) getTrade()).onFiatPaymentReceived(resultHandler, errorMessageHandler); } - public void onWithdrawRequest(String toAddress, Coin receiverAmount, ResultHandler resultHandler, FaultHandler faultHandler) { + public void onWithdrawRequest(String toAddress, Coin receiverAmount, KeyParameter aesKey, ResultHandler resultHandler, FaultHandler faultHandler) { checkNotNull(getTrade(), "trade must not be null"); - if (walletService.getWallet().isEncrypted()) { - walletPasswordWindow.onAesKey(aesKey -> doWithdrawRequest(toAddress, receiverAmount, aesKey, resultHandler, faultHandler)).show(); - } else - doWithdrawRequest(toAddress, receiverAmount, null, resultHandler, faultHandler); + + if (toAddress != null && toAddress.length() > 0) { + tradeManager.onWithdrawRequest( + toAddress, + receiverAmount, + aesKey, + getTrade(), + () -> { + resultHandler.handleResult(); + selectBestItem(); + }, + (errorMessage, throwable) -> { + log.error(errorMessage); + faultHandler.handleFault(errorMessage, throwable); + }); + } else { + faultHandler.handleFault("No receiver address defined", null); + } } public void onOpenDispute() { @@ -279,26 +293,6 @@ public class PendingTradesDataModel extends ActivatableDataModel { selectedItemProperty.set(item); } - private void doWithdrawRequest(String toAddress, Coin receiverAmount, KeyParameter aesKey, ResultHandler resultHandler, FaultHandler faultHandler) { - if (toAddress != null && toAddress.length() > 0) { - tradeManager.onWithdrawRequest( - toAddress, - receiverAmount, - aesKey, - getTrade(), - () -> { - resultHandler.handleResult(); - selectBestItem(); - }, - (errorMessage, throwable) -> { - log.error(errorMessage); - faultHandler.handleFault(errorMessage, throwable); - }); - } else { - faultHandler.handleFault("No receiver address defined", null); - } - } - private void tryOpenDispute(boolean isSupportTicket) { if (getTrade() != null) { Transaction depositTx = getTrade().getDepositTx(); diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java index 1f05e795f6..eac0180c55 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java @@ -23,6 +23,8 @@ import io.bitsquare.btc.AddressEntry; import io.bitsquare.btc.AddressEntryException; import io.bitsquare.btc.Restrictions; import io.bitsquare.btc.WalletService; +import io.bitsquare.common.handlers.FaultHandler; +import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.common.util.Tuple2; import io.bitsquare.gui.components.InputTextField; import io.bitsquare.gui.main.MainView; @@ -43,6 +45,7 @@ import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.Coin; +import org.spongycastle.crypto.params.KeyParameter; import static io.bitsquare.gui.util.FormBuilder.*; @@ -150,7 +153,7 @@ public class BuyerStep5View extends TradeStepView { if (!BitsquareApp.DEV_MODE && preferences.showAgain(key)) { preferences.dontShowAgain(key, true); new Notification().headLine("Trade completed") - .notification("You can withdraw your funds now to your external Bitcoin wallet.") + .notification("You can withdraw your funds now to your external Bitcoin wallet or transfer it to the Bitsquare wallet.") .autoClose() .show(); } @@ -222,18 +225,33 @@ public class BuyerStep5View extends TradeStepView { private void doWithdrawal(Coin receiverAmount) { useSavingsWalletButton.setDisable(true); withdrawToExternalWalletButton.setDisable(true); + String toAddress = withdrawAddressTextField.getText(); + ResultHandler resultHandler = this::handleTradeCompleted; + FaultHandler faultHandler = (errorMessage, throwable) -> { + useSavingsWalletButton.setDisable(false); + withdrawToExternalWalletButton.setDisable(false); + if (throwable != null && throwable.getMessage() != null) + new Popup().error(errorMessage + "\n\n" + throwable.getMessage()).show(); + else + new Popup().error(errorMessage).show(); + }; + if (model.dataModel.walletService.getWallet().isEncrypted()) { + model.dataModel.walletPasswordWindow.onAesKey(aesKey -> doWithdrawRequest(toAddress, receiverAmount, aesKey, resultHandler, faultHandler)) + .onClose(() -> { + useSavingsWalletButton.setDisable(false); + withdrawToExternalWalletButton.setDisable(false); + }) + .show(); + } else + doWithdrawRequest(toAddress, receiverAmount, null, resultHandler, faultHandler); + } - model.dataModel.onWithdrawRequest(withdrawAddressTextField.getText(), + private void doWithdrawRequest(String toAddress, Coin receiverAmount, KeyParameter aesKey, ResultHandler resultHandler, FaultHandler faultHandler) { + model.dataModel.onWithdrawRequest(toAddress, receiverAmount, - this::handleTradeCompleted, - (errorMessage, throwable) -> { - useSavingsWalletButton.setDisable(false); - withdrawToExternalWalletButton.setDisable(false); - if (throwable != null && throwable.getMessage() != null) - new Popup().error(errorMessage + "\n\n" + throwable.getMessage()).show(); - else - new Popup().error(errorMessage).show(); - }); + aesKey, + resultHandler, + faultHandler); } private void handleTradeCompleted() { diff --git a/gui/src/main/resources/i18n/displayStrings.properties b/gui/src/main/resources/i18n/displayStrings.properties index 46215a0f94..2b4c7d98ff 100644 --- a/gui/src/main/resources/i18n/displayStrings.properties +++ b/gui/src/main/resources/i18n/displayStrings.properties @@ -49,7 +49,7 @@ createOffer.amountPriceBox.error.message=An error occurred when placing the offe createOffer.validation.amountSmallerThanMinAmount=Amount cannot be smaller than minimum amount. createOffer.validation.minAmountLargerThanAmount=Minimum amount cannot be larger than amount. -createOffer.fundsBox.title=Fund your trade wallet +createOffer.fundsBox.title=Fund your offer createOffer.fundsBox.totalsNeeded=Funds needed: createOffer.fundsBox.totalsNeeded.prompt=Will be calculated from the bitcoin amount entered above createOffer.fundsBox.address=Trade wallet address: @@ -103,7 +103,7 @@ takeOffer.validation.amountSmallerThanMinAmount=Amount cannot be smaller than mi takeOffer.validation.amountLargerThanOfferAmount=Input amount cannot be higher than the amount defined in the offer. takeOffer.validation.amountLargerThanOfferAmountMinusFee=That input amount would create a dust change for the seller. -takeOffer.fundsBox.title=Fund your trade wallet +takeOffer.fundsBox.title=Fund your trade takeOffer.fundsBox.isOfferAvailable=Check if offer is available... takeOffer.fundsBox.totalsNeeded=Funds needed: takeOffer.fundsBox.totalsNeeded.prompt=Will be calculated from the bitcoin amount entered above