impl. feedback from aaron. improve popups, add warning for remove offer, deactivate mainnet,...

This commit is contained in:
Manfred Karrer 2015-11-17 20:54:03 +01:00
parent 2950f6e347
commit f9a31f4b8a
37 changed files with 425 additions and 281 deletions

View file

@ -167,7 +167,7 @@ public class BitsquareApp extends Application {
showFPSWindow();
else if (new KeyCodeCombination(KeyCode.E, KeyCombination.SHORTCUT_DOWN).match(keyEvent))
showEmptyWalletPopup();
else if (new KeyCodeCombination(KeyCode.A, KeyCombination.SHORTCUT_DOWN).match(keyEvent))
else if (new KeyCodeCombination(KeyCode.M, KeyCombination.SHORTCUT_DOWN).match(keyEvent))
showSendAlertMessagePopup();
});
@ -326,6 +326,7 @@ public class BitsquareApp extends Application {
private void restart() {
//TODO
stop();
//gracefulShutDown(UpdateFX::restartApp);
}
}

View file

@ -32,6 +32,7 @@ import org.bitcoinj.core.Coin;
public class BalanceTextField extends AnchorPane {
private static WalletService walletService;
private BalanceListener balanceListener;
public static void setWalletService(WalletService walletService) {
BalanceTextField.walletService = walletService;
@ -61,15 +62,20 @@ public class BalanceTextField extends AnchorPane {
public void setup(Address address, BSFormatter formatter) {
this.formatter = formatter;
walletService.addBalanceListener(new BalanceListener(address) {
balanceListener = new BalanceListener(address) {
@Override
public void onBalanceChanged(Coin balance) {
updateBalance(balance);
}
});
};
walletService.addBalanceListener(balanceListener);
updateBalance(walletService.getBalanceForAddress(address));
}
public void disarm() {
walletService.removeBalanceListener(balanceListener);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private methods

View file

@ -111,12 +111,16 @@ public abstract class PaymentMethodForm {
protected void addAllowedPeriod() {
long hours = paymentAccount.getPaymentMethod().getMaxTradePeriod() / 6;
String displayText = hours + " hours";
if (hours == 24)
if (hours == 1)
displayText = "1 hour";
else if (hours == 24)
displayText = "1 day";
if (hours > 24)
else if (hours > 24)
displayText = hours / 24 + " days";
addLabelTextField(gridPane, ++gridRow, "Max. allowed trade period:", displayText);
displayText += " (Max. permitted period until the trade needs to be completed)";
addLabelTextField(gridPane, ++gridRow, "Max. permitted trade period:", displayText);
}
abstract protected void autoFillNameTextField();

View file

@ -202,10 +202,16 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
log.debug("Wallet restored with seed words");
new Popup()
.information("Wallet restored successfully with the new seed words.\n\n" +
"You need to shut down and restart the application.")
.closeButtonText("Shut down")
.onClose(() -> BitsquareApp.shutDownHandler.run()).show();
//TODO
/* new Popup()
.information("Wallet restored successfully with the new seed words.\n\n" +
"You need to restart now the application.")
.closeButtonText("Restart")
.onClose(() -> BitsquareApp.restartDownHandler.run()).show();
.onClose(() -> BitsquareApp.restartDownHandler.run()).show();*/
}),
throwable -> UserThread.execute(() -> {
log.error(throwable.getMessage());

View file

@ -37,7 +37,6 @@ import io.bitsquare.gui.main.account.settings.AccountSettingsView;
import io.bitsquare.gui.main.offer.OfferView;
import io.bitsquare.gui.main.portfolio.PortfolioView;
import io.bitsquare.gui.main.portfolio.openoffer.OpenOffersView;
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesView;
import io.bitsquare.gui.popups.OfferDetailsPopup;
import io.bitsquare.gui.popups.Popup;
import io.bitsquare.gui.util.BSFormatter;
@ -226,9 +225,13 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
private void onShowFundsScreen() {
if (!BitsquareApp.DEV_MODE) {
if (model.getDisplaySecurityDepositInfo()) {
new Popup().information("To ensure that both traders behave fair they need to pay a security deposit.\n\n" +
new Popup().information("To ensure that both traders follow the trade protocol they need to pay a security deposit.\n\n" +
"The deposit will stay in your local trading wallet until the offer gets accepted by another trader.\n" +
"It will be refunded to you after the trade has successfully completed.").show();
"It will be refunded to you after the trade has successfully completed.\n\n" +
"You need to pay in the exact amount displayed to you from your external Bitcoin wallet into the " +
"Bitsquare trade wallet. The amount is the sum of the security deposit, the trading fee and " +
"the Bitcoin mining fee.\n" +
"You can see the details when you move the mouse over the question mark.").show();
model.onSecurityDepositInfoDisplayed();
}
@ -435,12 +438,16 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
UserThread.runAfter(() -> {
new Popup().headLine(BSResources.get("createOffer.success.headline"))
.message(BSResources.get("createOffer.success.info"))
.onClose(() -> {
navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class);
.actionButtonText("Go to \"Open offers\"")
.onAction(() -> {
close();
UserThread.runAfter(() ->
navigation.navigateTo(MainView.class, PortfolioView.class, OpenOffersView.class),
100, TimeUnit.MILLISECONDS);
})
.onClose(() -> close())
.show();
}, 300, TimeUnit.MILLISECONDS);
}, 100, TimeUnit.MILLISECONDS);
}
};
}

View file

@ -289,7 +289,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
if (newValue != null) {
if (offer.getState() == Offer.State.OFFER_FEE_PAID)
this.errorMessage.set(newValue +
"\n\nThe create offer fee is already paid. In the worst case you have lost that fee. " +
"\n\nThe offer fee is already paid. In the worst case you have lost that fee. " +
"We are sorry about that but keep in mind it is a very small amount.\n" +
"Please try to restart you application and check your network connection to see if you can resolve the issue.");
else

View file

@ -239,23 +239,31 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
private void onRemoveOpenOffer(Offer offer) {
if (model.isAuthenticated()) {
model.onRemoveOpenOffer(offer,
() -> {
log.debug("Remove offer was successful");
new Popup().information("You can withdraw the funds you paid in from the funds screens.").show();
navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class);
},
(message) -> {
log.error(message);
new Popup().warning("Remove offer failed:\n" + message).show();
});
new Popup().warning("Are you sure you want to remove that offer?\n" +
"The offer fee you have paid will be lost if you remove that offer.")
.actionButtonText("Remove offer")
.onAction(() -> doRemoveOffer(offer))
.closeButtonText("Don't remove the offer")
.show();
} else {
new Popup().warning("You need to wait until your client is authenticated in the network.\n" +
"That might take up to about 2 minutes at startup.").show();
}
}
private void doRemoveOffer(Offer offer) {
model.onRemoveOpenOffer(offer,
() -> {
log.debug("Remove offer was successful");
new Popup().information("You can withdraw the funds you paid in from the funds screens.").show();
navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class);
},
(message) -> {
log.error(message);
new Popup().warning("Remove offer failed:\n" + message).show();
});
}
private void showWarning(String masthead, String message, Class target) {
new Popup().information(masthead + "\n\n" + message)
.onAction(() -> {

View file

@ -127,6 +127,9 @@ class TakeOfferDataModel extends ActivatableDataModel {
void initWithData(Offer offer) {
this.offer = offer;
addressEntry = walletService.getAddressEntryByOfferId(offer.getId());
checkNotNull(addressEntry, "addressEntry must not be null");
ObservableList<PaymentAccount> possiblePaymentAccounts = getPossiblePaymentAccounts();
checkArgument(!possiblePaymentAccounts.isEmpty(), "possiblePaymentAccounts.isEmpty()");
paymentAccount = possiblePaymentAccounts.get(0);
@ -136,9 +139,6 @@ class TakeOfferDataModel extends ActivatableDataModel {
calculateVolume();
calculateTotalToPay();
addressEntry = walletService.getAddressEntryByOfferId(offer.getId());
checkNotNull(addressEntry, "addressEntry must not be null");
balanceListener = new BalanceListener(addressEntry.getAddress()) {
@Override
public void onBalanceChanged(@NotNull Coin balance) {
@ -255,6 +255,8 @@ class TakeOfferDataModel extends ActivatableDataModel {
amountAsCoin.get() != null &&
!amountAsCoin.get().isZero()) {
volumeAsFiat.set(new ExchangeRate(offer.getPrice()).coinToFiat(amountAsCoin.get()));
updateBalance(walletService.getBalanceForAddress(addressEntry.getAddress()));
}
}

View file

@ -225,12 +225,16 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
if (newValue && model.getTrade() != null && model.getTrade().errorMessageProperty().get() == null) {
UserThread.runAfter(() -> {
new Popup().information(BSResources.get("takeOffer.success.info"))
.onClose(() -> {
navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class);
.actionButtonText("Go to \"Open trades\"")
.onAction(() -> {
close();
UserThread.runAfter(() ->
navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class),
100, TimeUnit.MILLISECONDS);
})
.onClose(() -> close())
.show();
}, 300, TimeUnit.MILLISECONDS);
}, 100, TimeUnit.MILLISECONDS);
}
});
@ -322,7 +326,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
private void onTakeOffer() {
Offer offer = model.getOffer();
if (model.getShowTakeOfferConfirmation()) {
offerDetailsPopup.onTakeOffer(() -> model.onTakeOffer()).show(offer);
offerDetailsPopup.onTakeOffer(() -> model.onTakeOffer()).show(offer, model.dataModel.amountAsCoin.get());
} else {
if (model.hasAcceptedArbitrators()) {
model.onTakeOffer();
@ -351,9 +355,13 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
Dialog.Actions.CLOSE.handle(actionEvent);
}
});
new Popup().information("To ensure that both traders behave fair they need to pay a security deposit.\n\n" +
new Popup().information("To ensure that both traders follow the trade protocol they need to pay a security deposit.\n\n" +
"The deposit will stay in your local trading wallet until the offer gets accepted by another trader.\n" +
"It will be refunded to you after the trade has successfully completed.").show();
"It will be refunded to you after the trade has successfully completed.\n\n" +
"You need to pay in the exact amount displayed to you from your external Bitcoin wallet into the " +
"Bitsquare trade wallet. The amount is the sum of the trade amount, the security deposit, " +
"the trading fee and the Bitcoin mining fee.\n" +
"You can see the details when you move the mouse over the question mark.").show();
model.onSecurityDepositInfoDisplayed();
}

View file

@ -288,7 +288,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
"Please try to restart you application and check your network connection to see if you can resolve the issue.";
break;
case TAKER_FEE_PAID:
appendMsg = "\n\nThe take offer fee is already paid. In the worst case you have lost that fee. " +
appendMsg = "\n\nThe trading fee is already paid. In the worst case you have lost that fee. " +
"We are sorry about that but keep in mind it is a very small amount.\n" +
"Please try to restart you application and check your network connection to see if you can resolve the issue.";
break;

View file

@ -72,25 +72,34 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
table.setItems(model.getList());
}
private void onCancelOpenOffer(OpenOffer openOffer) {
private void onRemoveOpenOffer(OpenOffer openOffer) {
if (model.isAuthenticated()) {
model.onCancelOpenOffer(openOffer,
() -> {
log.debug("Remove offer was successful");
new Popup().information("You can withdraw the funds you paid in from the funds screens.")
.onClose(() -> navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class))
.show();
},
(message) -> {
log.error(message);
new Popup().warning("Remove offer failed:\n" + message).show();
});
new Popup().warning("Are you sure you want to remove that offer?\n" +
"The offer fee you have paid will be lost if you remove that offer.")
.actionButtonText("Remove offer")
.onAction(() -> doRemoveOpenOffer(openOffer))
.closeButtonText("Don't remove the offer")
.show();
} else {
new Popup().warning("You need to wait until your client is authenticated in the network.\n" +
"That might take up to about 2 minutes at startup.").show();
}
}
private void doRemoveOpenOffer(OpenOffer openOffer) {
model.onCancelOpenOffer(openOffer,
() -> {
log.debug("Remove offer was successful");
new Popup().information("You can withdraw the funds you paid in from the funds screens.")
.onClose(() -> navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class))
.show();
},
(message) -> {
log.error(message);
new Popup().warning("Remove offer failed:\n" + message).show();
});
}
/* private void openOfferDetails(OpenOfferListItem item) {
Offer offer = item.getOffer();
int rowIndex = 0;
@ -284,7 +293,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
super.updateItem(item, empty);
if (item != null) {
button.setOnAction(event -> onCancelOpenOffer(item.getOpenOffer()));
button.setOnAction(event -> onRemoveOpenOffer(item.getOpenOffer()));
setGraphic(button);
} else {
setGraphic(null);

View file

@ -136,8 +136,7 @@ public class PendingTradesDataModel extends ActivatableDataModel {
if (item == null) {
trade = null;
tradeProperty.set(null);
}
else {
} else {
trade = item.getTrade();
tradeProperty.set(trade);
@ -169,17 +168,17 @@ public class PendingTradesDataModel extends ActivatableDataModel {
}
private void doWithdrawRequest(String toAddress, KeyParameter aesKey) {
tradeManager.onWithdrawRequest(
toAddress,
aesKey,
trade,
() -> {
UserThread.execute(() -> navigation.navigateTo(MainView.class, PortfolioView.class, ClosedTradesView.class));
},
(errorMessage, throwable) -> {
log.error(errorMessage);
new Popup().error("An error occurred:\n" + throwable.getMessage()).show();
});
if (toAddress != null && toAddress.length() > 0) {
tradeManager.onWithdrawRequest(
toAddress,
aesKey,
trade,
() -> UserThread.execute(() -> navigation.navigateTo(MainView.class, PortfolioView.class, ClosedTradesView.class)),
(errorMessage, throwable) -> {
log.error(errorMessage);
new Popup().error("An error occurred:\n" + throwable.getMessage()).show();
});
}
}
public void onOpenDispute() {

View file

@ -60,9 +60,11 @@ public class CompletedView extends TradeStepDetailsView {
@Override
public void doActivate() {
super.doActivate();
withdrawAddressTextField.focusedProperty().addListener(focusedPropertyListener);
withdrawAddressTextField.setValidator(model.getBtcAddressValidator());
withdrawButton.disableProperty().bind(model.getWithdrawalButtonDisable());
// TODO valid. handler need improvement
//withdrawAddressTextField.focusedProperty().addListener(focusedPropertyListener);
//withdrawAddressTextField.setValidator(model.getBtcAddressValidator());
// withdrawButton.disableProperty().bind(model.getWithdrawalButtonDisable());
// We need to handle both cases: Address not set and address already set (when returning from other view)
// We get address validation after focus out, so first make sure we loose focus and then set it again as hint for user to put address in
@ -78,8 +80,8 @@ public class CompletedView extends TradeStepDetailsView {
@Override
public void doDeactivate() {
super.doDeactivate();
withdrawAddressTextField.focusedProperty().removeListener(focusedPropertyListener);
withdrawButton.disableProperty().unbind();
//withdrawAddressTextField.focusedProperty().removeListener(focusedPropertyListener);
// withdrawButton.disableProperty().unbind();
}

View file

@ -111,19 +111,17 @@ public class ConfirmPaymentReceivedView extends TradeStepDetailsView {
Preferences preferences = model.dataModel.getPreferences();
String key = PopupId.PAYMENT_RECEIVED;
if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE) {
new Popup().information("Please note that as soon you have confirmed that you have received the " +
"payment the locked Bitcoin will be released.\n" +
"There is no way to reverse a Bitcoin payment. Confirm only if you are sure.")
.onClose(() -> preferences.dontShowAgain(key))
new Popup().headLine("Confirmation")
.message("Do you have received the payment from your trading partner?\n\n" +
"Please note that as soon you have confirmed the locked Bitcoin will be released.\n" +
"There is no way to reverse a Bitcoin payment.")
.dontShowAgainId(key, preferences)
.actionButtonText("Yes I have received the payment")
.closeButtonText("No")
.onAction(() -> confirmPaymentReceived())
.show();
} else {
confirmFiatReceivedButton.setDisable(true);
statusProgressIndicator.setVisible(true);
statusProgressIndicator.setProgress(-1);
statusLabel.setText("Sending message to trading partner...");
model.fiatPaymentReceived();
confirmPaymentReceived();
}
} else {
new Popup().warning("You need to wait until your client is authenticated in the network.\n" +
@ -131,6 +129,16 @@ public class ConfirmPaymentReceivedView extends TradeStepDetailsView {
}
}
private void confirmPaymentReceived() {
confirmFiatReceivedButton.setDisable(true);
statusProgressIndicator.setVisible(true);
statusProgressIndicator.setProgress(-1);
statusLabel.setText("Sending message to trading partner...");
model.fiatPaymentReceived();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setters

View file

@ -143,18 +143,15 @@ public class StartPaymentView extends TradeStepDetailsView {
if (model.isAuthenticated()) {
String key = PopupId.PAYMENT_SENT;
if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE) {
new Popup().information("You are confirming that you have transferred the payment to your trading partner.\n" +
"Please click the \"Payment started\" button only if you have completed the transfer.")
.onClose(() -> preferences.dontShowAgain(key))
new Popup().headLine("Confirmation")
.message("Do you have transferred the payment to your trading partner?")
.dontShowAgainId(key, preferences)
.actionButtonText("Yes I have started the payment")
.closeButtonText("No")
.onAction(() -> confirmPaymentStarted())
.show();
} else {
paymentStartedButton.setDisable(true);
statusProgressIndicator.setVisible(true);
statusProgressIndicator.setProgress(-1);
statusLabel.setText("Sending message to trading partner...");
model.fiatPaymentStarted();
confirmPaymentStarted();
}
} else {
new Popup().warning("You need to wait until your client is authenticated in the network.\n" +
@ -162,6 +159,16 @@ public class StartPaymentView extends TradeStepDetailsView {
}
}
private void confirmPaymentStarted() {
paymentStartedButton.setDisable(true);
statusProgressIndicator.setVisible(true);
statusProgressIndicator.setProgress(-1);
statusLabel.setText("Sending message to trading partner...");
model.fiatPaymentStarted();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Build view

View file

@ -52,7 +52,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
btcDenominationComboBox = addLabelComboBox(root, gridRow, "Bitcoin denomination:", Layout.FIRST_ROW_DISTANCE).second;
blockExplorerComboBox = addLabelComboBox(root, ++gridRow, "Bitcoin block explorer:").second;
useAnimationsCheckBox = addLabelCheckBox(root, ++gridRow, "Use animations:", "").second;
useEffectsCheckBox = addLabelCheckBox(root, ++gridRow, "Use efects:", "").second;
useEffectsCheckBox = addLabelCheckBox(root, ++gridRow, "Use effects:", "").second;
showPlaceOfferConfirmationCheckBox = addLabelCheckBox(root, ++gridRow, "Show confirmation at place offer:", "").second;
showTakeOfferConfirmationCheckBox = addLabelCheckBox(root, ++gridRow, "Show confirmation at take offer:", "").second;
autoSelectArbitratorsCheckBox = addLabelCheckBox(root, ++gridRow, "Auto select arbitrators by language:", "").second;

View file

@ -153,10 +153,8 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
private void onSelectNetwork() {
if (netWorkComboBox.getSelectionModel().getSelectedItem() != preferences.getBitcoinNetwork()) {
if (netWorkComboBox.getSelectionModel().getSelectedItem() == BitcoinNetwork.MAINNET) {
new Popup().warning("The application is under heavy development. " +
"Using the mainnet network with Bitcoin is not recommended at that stage.\n\n" +
"Are you sure you want to switch to mainnet?")
.onAction(() -> selectNetwork())
new Popup().warning("The application needs more tested before it can be used in mainnet.\n" +
"Please follow our mailing list to get informed when Bitsquare will be ready for mainnet.")
.onClose(() -> UserThread.execute(() -> netWorkComboBox.getSelectionModel().select(preferences.getBitcoinNetwork())))
.show();
} else {
@ -166,10 +164,14 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
}
private void selectNetwork() {
preferences.setBitcoinNetwork(netWorkComboBox.getSelectionModel().getSelectedItem());
new Popup().warning("You need to restart the application to apply the change of the Bitcoin network..\n\n" +
"Do you want to restart now?")
.onAction(() -> BitsquareApp.restartDownHandler.run())
//TODO restart
new Popup().warning("You need to shut down and restart the application to apply the change of the Bitcoin network.\n\n" +
"Do you want to shut down now?")
.onAction(() -> {
preferences.setBitcoinNetwork(netWorkComboBox.getSelectionModel().getSelectedItem());
UserThread.runAfter(() -> BitsquareApp.shutDownHandler.run(), 1);
})
.onClose(() -> netWorkComboBox.getSelectionModel().select(preferences.getBitcoinNetwork()))
.show();
}
}

View file

@ -109,8 +109,7 @@ public class ContractPopup extends Popup {
Layout.FIRST_ROW_DISTANCE).second.setMouseTransparent(false);
addLabelTextField(gridPane, ++rowIndex, "Offer date:", formatter.formatDateTime(offer.getDate()));
addLabelTextField(gridPane, ++rowIndex, "Trade date:", formatter.formatDateTime(dispute.getTradeDate()));
String direction = offer.getDirection() == Offer.Direction.BUY ? "Offerer as buyer / Taker as seller" : "Offerer as seller / Taker as buyer";
addLabelTextField(gridPane, ++rowIndex, "Trade type:", direction);
addLabelTextField(gridPane, ++rowIndex, "Trade type:", formatter.getDirectionDescription(offer.getDirection()));
addLabelTextField(gridPane, ++rowIndex, "Price:", formatter.formatFiat(offer.getPrice()) + " " + offer.getCurrencyCode());
addLabelTextField(gridPane, ++rowIndex, "Trade amount:", formatter.formatCoinWithCode(contract.getTradeAmount()));
addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "Buyer bitcoin address:",
@ -144,8 +143,8 @@ public class ContractPopup extends Popup {
}
//addLabelTextField(gridPane, ++rowIndex, "Buyer Bitsquare account ID:", contract.getBuyerAccountId()).second.setMouseTransparent(false);
//addLabelTextField(gridPane, ++rowIndex, "Seller Bitsquare account ID:", contract.getSellerAccountId()).second.setMouseTransparent(false);
addLabelTxIdTextField(gridPane, ++rowIndex, "Create offer fee transaction ID:", offer.getOfferFeePaymentTxID());
addLabelTxIdTextField(gridPane, ++rowIndex, "Take offer fee transaction ID:", contract.takeOfferFeeTxID);
addLabelTxIdTextField(gridPane, ++rowIndex, "Offer fee transaction ID:", offer.getOfferFeePaymentTxID());
addLabelTxIdTextField(gridPane, ++rowIndex, "Trading fee transaction ID:", contract.takeOfferFeeTxID);
if (dispute.getDepositTxSerialized() != null)
addLabelTxIdTextField(gridPane, ++rowIndex, "Deposit transaction ID:", dispute.getDepositTxId());
if (dispute.getPayoutTxSerialized() != null)

View file

@ -54,8 +54,8 @@ public class FirstTimeWebViewPopup extends WebViewPopup {
return this;
}
public FirstTimeWebViewPopup id(String id) {
this.id = id;
public FirstTimeWebViewPopup id(String dontShowAgainId) {
this.id = dontShowAgainId;
return this;
}

View file

@ -35,6 +35,8 @@ import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import org.bitcoinj.core.Coin;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -52,6 +54,7 @@ public class OfferDetailsPopup extends Popup {
private User user;
private final Navigation navigation;
private Offer offer;
private Coin tradeAmount;
private Optional<Consumer<Offer>> placeOfferHandlerOptional = Optional.empty();
private Optional<Runnable> takeOfferHandlerOptional = Optional.empty();
@ -68,6 +71,18 @@ public class OfferDetailsPopup extends Popup {
this.navigation = navigation;
}
public OfferDetailsPopup show(Offer offer, Coin tradeAmount) {
this.offer = offer;
this.tradeAmount = tradeAmount;
rowIndex = -1;
width = 850;
createGridPane();
addContent();
createPopup();
return this;
}
public OfferDetailsPopup show(Offer offer) {
this.offer = offer;
@ -110,25 +125,36 @@ public class OfferDetailsPopup extends Popup {
}
private void addContent() {
int rows = 11;
int rows = 5;
if (!takeOfferHandlerOptional.isPresent())
rows++;
addTitledGroupBg(gridPane, ++rowIndex, rows, "Offer");
addLabelTextField(gridPane, rowIndex, "Offer type:", formatter.getDirectionDescription(offer.getDirection()), Layout.FIRST_ROW_DISTANCE);
addLabelTextField(gridPane, ++rowIndex, "Currency:", offer.getCurrencyCode());
addLabelTextField(gridPane, ++rowIndex, "Price:", formatter.formatFiat(offer.getPrice()) + " " + offer.getCurrencyCode() + "/" + "BTC");
if (takeOfferHandlerOptional.isPresent()) {
addLabelTextField(gridPane, ++rowIndex, "Trade amount:", formatter.formatCoinWithCode(tradeAmount));
} else {
addLabelTextField(gridPane, ++rowIndex, "Amount:", formatter.formatCoinWithCode(offer.getAmount()));
addLabelTextField(gridPane, ++rowIndex, "Min. amount:", formatter.formatCoinWithCode(offer.getMinAmount()));
}
addLabelTextField(gridPane, ++rowIndex, "Payment method:", BSResources.get(offer.getPaymentMethod().getId()));
rows = 3;
if (offer.getPaymentMethodCountryCode() != null)
rows++;
if (offer.getOfferFeePaymentTxID() != null)
rows++;
if (offer.getAcceptedCountryCodes() != null)
rows++;
if (placeOfferHandlerOptional.isPresent())
rows -= 2;
/* if (placeOfferHandlerOptional.isPresent())
rows -= 2;*/
addTitledGroupBg(gridPane, ++rowIndex, rows, "Offer details");
addLabelTextField(gridPane, rowIndex, "Offer ID:", offer.getId(), Layout.FIRST_ROW_DISTANCE);
addTitledGroupBg(gridPane, ++rowIndex, rows, "Details", Layout.GROUP_DISTANCE);
addLabelTextField(gridPane, rowIndex, "Offer ID:", offer.getId(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
addLabelTextField(gridPane, ++rowIndex, "Creation date:", formatter.formatDateTime(offer.getDate()));
addLabelTextField(gridPane, ++rowIndex, "Offer direction:", Offer.Direction.BUY.name());
addLabelTextField(gridPane, ++rowIndex, "Currency:", offer.getCurrencyCode());
addLabelTextField(gridPane, ++rowIndex, "Price:", formatter.formatFiat(offer.getPrice()) + " " + offer.getCurrencyCode() + "/" + "BTC");
addLabelTextField(gridPane, ++rowIndex, "Amount:", formatter.formatCoinWithCode(offer.getAmount()));
addLabelTextField(gridPane, ++rowIndex, "Min. amount:", formatter.formatCoinWithCode(offer.getMinAmount()));
addLabelTextField(gridPane, ++rowIndex, "Payment method:", BSResources.get(offer.getPaymentMethod().getId()));
if (offer.getPaymentMethodCountryCode() != null)
addLabelTextField(gridPane, ++rowIndex, "Offerers country of bank:", offer.getPaymentMethodCountryCode());
if (offer.getAcceptedCountryCodes() != null) {
@ -141,61 +167,27 @@ public class OfferDetailsPopup extends Popup {
tooltip = new Tooltip(CountryUtil.getNamesByCodesString(offer.getAcceptedCountryCodes()));
}
TextField acceptedCountries = addLabelTextField(gridPane, ++rowIndex, "Accepted taker countries:", countries).second;
if (tooltip != null) acceptedCountries.setTooltip(new Tooltip());
if (tooltip != null) {
acceptedCountries.setMouseTransparent(false);
acceptedCountries.setTooltip(tooltip);
}
}
addLabelTextField(gridPane, ++rowIndex, "Accepted arbitrators:", formatter.arbitratorAddressesToString(offer.getArbitratorAddresses()));
if (offer.getOfferFeePaymentTxID() != null)
addLabelTxIdTextField(gridPane, ++rowIndex, "Create offer fee transaction ID:", offer.getOfferFeePaymentTxID());
addLabelTxIdTextField(gridPane, ++rowIndex, "Offer fee transaction ID:", offer.getOfferFeePaymentTxID());
if (placeOfferHandlerOptional.isPresent()) {
Tuple2<Button, Button> tuple = add2ButtonsAfterGroup(gridPane, ++rowIndex, "Confirm place offer", "Cancel");
Button placeButton = tuple.first;
placeButton.setOnAction(e -> {
if (user.getAcceptedArbitrators().size() > 0) {
placeOfferHandlerOptional.get().accept(offer);
} else {
new Popup().warning("You have no arbitrator selected.\n" +
"Please select at least one arbitrator.").show();
addTitledGroupBg(gridPane, ++rowIndex, 1, "Commitment", Layout.GROUP_DISTANCE);
addLabelTextField(gridPane, rowIndex, "Please note:", Offer.TAC_OFFERER, Layout.FIRST_ROW_AND_GROUP_DISTANCE);
navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class, ArbitratorSelectionView.class);
}
hide();
});
Button cancelButton = tuple.second;
cancelButton.setOnAction(e -> {
closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run());
hide();
});
CheckBox checkBox = addCheckBox(gridPane, ++rowIndex, "Don't show again", 5);
checkBox.setSelected(!preferences.getShowPlaceOfferConfirmation());
checkBox.setOnAction(e -> preferences.setShowPlaceOfferConfirmation(!checkBox.isSelected()));
Button cancelButton = addConfirmButton(true);
addCancelButton(cancelButton, true);
} else if (takeOfferHandlerOptional.isPresent()) {
Tuple2<Button, Button> tuple = add2ButtonsAfterGroup(gridPane, ++rowIndex, "Confirm take offer", "Cancel");
Button placeButton = tuple.first;
placeButton.setOnAction(e -> {
if (user.getAcceptedArbitrators().size() > 0) {
takeOfferHandlerOptional.get().run();
} else {
new Popup().warning("You have no arbitrator selected.\n" +
"Please select at least one arbitrator.").show();
addTitledGroupBg(gridPane, ++rowIndex, 1, "Contract", Layout.GROUP_DISTANCE);
addLabelTextField(gridPane, rowIndex, "Terms and conditions:", Offer.TAC_TAKER, Layout.FIRST_ROW_AND_GROUP_DISTANCE);
navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class, ArbitratorSelectionView.class);
}
hide();
});
Button cancelButton = tuple.second;
cancelButton.setOnAction(e -> {
closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run());
hide();
});
CheckBox checkBox = addCheckBox(gridPane, ++rowIndex, "Don't show again", 5);
checkBox.setPadding(new Insets(20, 0, 25, 0));
checkBox.setSelected(!preferences.getShowTakeOfferConfirmation());
checkBox.setOnAction(e -> preferences.setShowTakeOfferConfirmation(!checkBox.isSelected()));
Button cancelButton = addConfirmButton(false);
addCancelButton(cancelButton, false);
} else {
Button cancelButton = addButtonAfterGroup(gridPane, ++rowIndex, "Close");
cancelButton.setOnAction(e -> {
@ -204,4 +196,44 @@ public class OfferDetailsPopup extends Popup {
});
}
}
@NotNull
private Button addConfirmButton(boolean isPlaceOffer) {
Tuple2<Button, Button> tuple = add2ButtonsAfterGroup(gridPane,
++rowIndex,
isPlaceOffer ? "Confirm place offer" : "Confirm take offer",
"Cancel");
Button placeButton = tuple.first;
placeButton.setOnAction(e -> {
if (user.getAcceptedArbitrators().size() > 0) {
if (isPlaceOffer)
placeOfferHandlerOptional.get().accept(offer);
else
takeOfferHandlerOptional.get().run();
} else {
new Popup().warning("You have no arbitrator selected.\n" +
"Please select at least one arbitrator.").show();
navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class, ArbitratorSelectionView.class);
}
hide();
});
return tuple.second;
}
private void addCancelButton(Button cancelButton, boolean isPlaceOffer) {
cancelButton.setOnAction(e -> {
closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run());
hide();
});
CheckBox checkBox = addCheckBox(gridPane, ++rowIndex, "Don't show again", 5);
if (isPlaceOffer) {
checkBox.setSelected(!preferences.getShowPlaceOfferConfirmation());
checkBox.setOnAction(e -> preferences.setShowPlaceOfferConfirmation(!checkBox.isSelected()));
} else {
checkBox.setSelected(!preferences.getShowTakeOfferConfirmation());
checkBox.setOnAction(e -> preferences.setShowTakeOfferConfirmation(!checkBox.isSelected()));
}
}
}

View file

@ -21,15 +21,13 @@ import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.util.Transitions;
import io.bitsquare.locale.BSResources;
import io.bitsquare.user.Preferences;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.Separator;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Modality;
@ -43,6 +41,8 @@ import org.slf4j.LoggerFactory;
import java.time.Duration;
import java.util.Optional;
import static io.bitsquare.gui.util.FormBuilder.addCheckBox;
public class Popup {
protected final Logger log = LoggerFactory.getLogger(this.getClass());
@ -66,6 +66,8 @@ public class Popup {
private boolean showProgressIndicator;
private Button actionButton;
protected Label headLineLabel;
private String dontShowAgainId;
private Preferences preferences;
///////////////////////////////////////////////////////////////////////////////////////////
@ -87,6 +89,7 @@ public class Popup {
addReportErrorButtons();
addCloseButton();
addDontShowAgainCheckBox();
createPopup();
return this;
}
@ -164,6 +167,12 @@ public class Popup {
return this;
}
public Popup dontShowAgainId(String dontShowAgainId, Preferences preferences) {
this.dontShowAgainId = dontShowAgainId;
this.preferences = preferences;
return this;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
@ -297,6 +306,17 @@ public class Popup {
gridPane.getChildren().add(progressIndicator);
}
private void addDontShowAgainCheckBox() {
if (dontShowAgainId != null && preferences != null) {
CheckBox dontShowAgain = addCheckBox(gridPane, ++rowIndex, "Don't show again", 10);
GridPane.setHalignment(dontShowAgain, HPos.RIGHT);
dontShowAgain.setOnAction(e -> {
if (dontShowAgain.isSelected())
preferences.dontShowAgain(dontShowAgainId);
});
}
}
protected void addCloseButton() {
closeButton = new Button(closeButtonText == null ? "Close" : closeButtonText);
closeButton.setOnAction(event -> {
@ -333,12 +353,11 @@ public class Popup {
GridPane.setColumnIndex(closeButton, 1);
gridPane.getChildren().add(closeButton);
}
}
protected void setTruncatedMessage() {
if (message != null && message.length() > 500)
truncatedMessage = message.substring(0, 500) + "...";
if (message != null && message.length() > 600)
truncatedMessage = message.substring(0, 600) + "...";
else
truncatedMessage = message;
}

View file

@ -90,7 +90,15 @@ public class TradeDetailsPopup extends Popup {
Offer offer = trade.getOffer();
Contract contract = trade.getContract();
int rows = 7;
int rows = 5;
addTitledGroupBg(gridPane, ++rowIndex, rows, "Trade");
addLabelTextField(gridPane, rowIndex, "Trade type:", formatter.getDirectionDescription(offer.getDirection()), Layout.FIRST_ROW_DISTANCE);
addLabelTextField(gridPane, ++rowIndex, "Currency:", offer.getCurrencyCode());
addLabelTextField(gridPane, ++rowIndex, "Price:", formatter.formatFiat(offer.getPrice()) + " " + offer.getCurrencyCode());
addLabelTextField(gridPane, ++rowIndex, "Trade amount:", formatter.formatCoinWithCode(trade.getTradeAmount()));
addLabelTextField(gridPane, ++rowIndex, "Payment method:", BSResources.get(offer.getPaymentMethod().getId()));
rows = 4;
PaymentAccountContractData buyerPaymentAccountContractData = null;
PaymentAccountContractData sellerPaymentAccountContractData = null;
@ -98,6 +106,8 @@ public class TradeDetailsPopup extends Popup {
rows++;
if (contract != null) {
rows++;
buyerPaymentAccountContractData = contract.getBuyerPaymentAccountContractData();
sellerPaymentAccountContractData = contract.getSellerPaymentAccountContractData();
if (buyerPaymentAccountContractData != null)
@ -120,13 +130,9 @@ public class TradeDetailsPopup extends Popup {
if (trade.errorMessageProperty().get() != null)
rows += 2;
addTitledGroupBg(gridPane, ++rowIndex, rows, "Trade details");
addLabelTextField(gridPane, rowIndex, "Trade ID:", trade.getId(), Layout.FIRST_ROW_DISTANCE);
addTitledGroupBg(gridPane, ++rowIndex, rows, "Details", Layout.GROUP_DISTANCE);
addLabelTextField(gridPane, rowIndex, "Trade ID:", trade.getId(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
addLabelTextField(gridPane, ++rowIndex, "Trade date:", formatter.formatDateTime(trade.getDate()));
String direction = offer.getDirection() == Offer.Direction.BUY ? "Offerer as buyer / Taker as seller" : "Offerer as seller / Taker as buyer";
addLabelTextField(gridPane, ++rowIndex, "Offer direction:", direction);
addLabelTextField(gridPane, ++rowIndex, "Price:", formatter.formatFiat(offer.getPrice()) + " " + offer.getCurrencyCode());
addLabelTextField(gridPane, ++rowIndex, "Trade amount:", formatter.formatCoinWithCode(trade.getTradeAmount()));
addLabelTextField(gridPane, ++rowIndex, "Selected arbitrator:", trade.getArbitratorAddress().getFullAddress());
if (contract != null) {
@ -144,15 +150,22 @@ public class TradeDetailsPopup extends Popup {
addLabelTextField(gridPane, ++rowIndex, "Payment method:", BSResources.get(contract.getPaymentMethodName()));
}
addLabelTxIdTextField(gridPane, ++rowIndex, "Create offer fee transaction ID:", offer.getOfferFeePaymentTxID());
addLabelTxIdTextField(gridPane, ++rowIndex, "Offer fee transaction ID:", offer.getOfferFeePaymentTxID());
if (contract != null && contract.takeOfferFeeTxID != null)
addLabelTxIdTextField(gridPane, ++rowIndex, "Take offer fee transaction ID:", contract.takeOfferFeeTxID);
addLabelTxIdTextField(gridPane, ++rowIndex, "Trading fee transaction ID:", contract.takeOfferFeeTxID);
if (trade.getDepositTx() != null)
addLabelTxIdTextField(gridPane, ++rowIndex, "Deposit transaction ID:", trade.getDepositTx().getHashAsString());
if (trade.getPayoutTx() != null)
addLabelTxIdTextField(gridPane, ++rowIndex, "Payout transaction ID:", trade.getPayoutTx().getHashAsString());
if (contract != null) {
TextArea textArea = addLabelTextArea(gridPane, ++rowIndex, "Contract in JSON format:", trade.getContractAsJson()).second;
textArea.setText(trade.getContractAsJson());
textArea.setPrefHeight(50);
textArea.setEditable(false);
}
if (trade.errorMessageProperty().get() != null) {
TextArea textArea = addLabelTextArea(gridPane, ++rowIndex, "Error message:", "").second;
textArea.setText(trade.errorMessageProperty().get());
@ -169,26 +182,6 @@ public class TradeDetailsPopup extends Popup {
TextField state = addLabelTextField(gridPane, ++rowIndex, "Trade state:").second;
state.setText(trade.getState().getPhase().name());
//TODO better msg display
/* switch (trade.getTradeState().getPhase()) {
case PREPARATION:
state.setText("Take offer fee is already paid.");
break;
case TAKER_FEE_PAID:
state.setText("Take offer fee is already paid.");
break;
case DEPOSIT_PAID:
case FIAT_SENT:
case FIAT_RECEIVED:
state.setText("Deposit is already paid.");
break;
case PAYOUT_PAID:
break;
case WITHDRAWN:
break;
case DISPUTE:
break;
}*/
}
Button cancelButton = addButtonAfterGroup(gridPane, ++rowIndex, "Close");

View file

@ -125,8 +125,7 @@ public class BSFormatter {
log.warn("Exception at formatBtc: " + t.toString());
return "";
}
}
else {
} else {
return "";
}
}
@ -141,8 +140,7 @@ public class BSFormatter {
log.warn("Exception at formatBtcWithCode: " + t.toString());
return "";
}
}
else {
} else {
return "";
}
}
@ -155,8 +153,7 @@ public class BSFormatter {
log.warn("Exception at parseToBtc: " + t.toString());
return Coin.ZERO;
}
}
else {
} else {
return Coin.ZERO;
}
}
@ -208,8 +205,7 @@ public class BSFormatter {
log.warn("Exception at formatFiat: " + t.toString());
return "";
}
}
else {
} else {
return "";
}
}
@ -223,8 +219,7 @@ public class BSFormatter {
log.warn("Exception at formatFiatWithCode: " + t.toString());
return "";
}
}
else {
} else {
return "";
}
}
@ -238,8 +233,7 @@ public class BSFormatter {
return Fiat.valueOf(currencyCode, 0);
}
}
else {
} else {
return Fiat.valueOf(currencyCode, 0);
}
}
@ -374,4 +368,8 @@ public class BSFormatter {
return "";
}
}
public String getDirectionDescription(Offer.Direction direction) {
return direction == Offer.Direction.BUY ? "Offerer as Bitcoin buyer / Taker as Bitcoin seller" : "Offerer as Bitcoin seller / Taker as Bitcoin buyer";
}
}

View file

@ -17,7 +17,7 @@ arising from, out of or in connection with the software or the use or other deal
2. The user is responsible to use the software in compliance with local laws.
<br/><br/>
3. The user confirms that he has read and agreed to the rules defined in our
<a href="https://github.com/bitsquare/bitsquare/wiki/Dispute-process" target="_blank">wiki</a> regrading the dispute
<a href="https://github.com/bitsquare/bitsquare/wiki/Dispute-process" target="_blank">Wiki</a> regrading the dispute
process.<br/>
</body>
</html>

View file

@ -23,13 +23,12 @@
</head>
<body>
<h1>Information</h1>
Bitsquare does not use a global wallet.<br/>
For every trade a dedicated wallet will be created. Funding of the wallet will be done just in time when it is needed.
For instance when you create an offer or
when you take an offer. Withdrawing from your funds can be done after a trade has been completed.<br/>
That separation of addresses helps to protect users privacy and not leaking information of previous trades to new
Bitsquare does not use a single application wallet, but dedicated wallets for every trade.<br/>
Funding of the wallet will be done when needed, for instance when you create or take an offer.
Withdrawing funds can be done after a trade is completed.<br/>
Dedicated wallets help protect user privacy and prevent leaking information of previous trades to other
traders.<br/>
Please read more background information to that topic at the Bitsquare <a href="https://bitsquare.io/faq/#tradeWallet"
For more background information please see the Bitsquare <a href="https://bitsquare.io/faq/#tradeWallet"
target="_blank">FAQ</a>.
</body>
</html>