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

@ -150,7 +150,7 @@ public class CountryUtil {
} }
public static String getNamesByCodesString(List<String> countryCodes) { public static String getNamesByCodesString(List<String> countryCodes) {
return getNamesByCodes(countryCodes).stream().collect(Collectors.joining(", ")); return getNamesByCodes(countryCodes).stream().collect(Collectors.joining(",\n"));
} }
private static final String[] countryCodes = new String[]{"AE", "AL", "AR", "AT", "AU", "BA", "BE", "BG", "BH", private static final String[] countryCodes = new String[]{"AE", "AL", "AR", "AT", "AU", "BA", "BE", "BG", "BH",

View file

@ -37,11 +37,14 @@ public class SepaAccountContractData extends PaymentAccountContractData implemen
private String holderName; private String holderName;
private String iban; private String iban;
private String bic; private String bic;
private Set<String> acceptedCountryCodes; // Dont use a set here as we need a deterministic ordering, otherwise the contract hash does not match
private ArrayList<String> acceptedCountryCodes;
public SepaAccountContractData(String paymentMethod, String id, int maxTradePeriod) { public SepaAccountContractData(String paymentMethod, String id, int maxTradePeriod) {
super(paymentMethod, id, maxTradePeriod); super(paymentMethod, id, maxTradePeriod);
acceptedCountryCodes = CountryUtil.getAllSepaCountries().stream().map(e -> e.code).collect(Collectors.toSet()); Set<String> acceptedCountryCodesAsSet = CountryUtil.getAllSepaCountries().stream().map(e -> e.code).collect(Collectors.toSet());
acceptedCountryCodes = new ArrayList<>(acceptedCountryCodesAsSet);
acceptedCountryCodes.sort((a, b) -> a.compareTo(b));
} }
public void setHolderName(String holderName) { public void setHolderName(String holderName) {
@ -69,17 +72,17 @@ public class SepaAccountContractData extends PaymentAccountContractData implemen
} }
public void addAcceptedCountry(String countryCode) { public void addAcceptedCountry(String countryCode) {
if (!acceptedCountryCodes.contains(countryCode))
acceptedCountryCodes.add(countryCode); acceptedCountryCodes.add(countryCode);
} }
public void removeAcceptedCountry(String countryCode) { public void removeAcceptedCountry(String countryCode) {
if (acceptedCountryCodes.contains(countryCode))
acceptedCountryCodes.remove(countryCode); acceptedCountryCodes.remove(countryCode);
} }
public List<String> getAcceptedCountryCodes() { public List<String> getAcceptedCountryCodes() {
List<String> sortedList = new ArrayList<>(acceptedCountryCodes); return acceptedCountryCodes;
sortedList.sort((a, b) -> a.compareTo(b));
return sortedList;
} }
@Override @Override

View file

@ -38,11 +38,13 @@ public class Contract implements Serializable {
@JsonExclude @JsonExclude
public static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; public static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
public static final String TAC = "I commit to the trade conditions as defined above.";
public final Offer offer; public final Offer offer;
private final long tradeAmount; private final long tradeAmount;
public final String takeOfferFeeTxID; public final String takeOfferFeeTxID;
public final Address arbitratorAddress; public final Address arbitratorAddress;
private final boolean isBuyerOffererOrSellerTaker; private final boolean isBuyerOffererAndSellerTaker;
private final String offererAccountId; private final String offererAccountId;
private final String takerAccountId; private final String takerAccountId;
private final PaymentAccountContractData offererPaymentAccountContractData; private final PaymentAccountContractData offererPaymentAccountContractData;
@ -62,17 +64,13 @@ public class Contract implements Serializable {
@JsonExclude @JsonExclude
private final byte[] takerBtcPubKey; private final byte[] takerBtcPubKey;
// TODO some basic TAC
public final String tac = "With my signature I commit to the trading agreement of Bitsquare and to fulfill the trade as defined there.";
public Contract(Offer offer, public Contract(Offer offer,
Coin tradeAmount, Coin tradeAmount,
String takeOfferFeeTxID, String takeOfferFeeTxID,
Address buyerAddress, Address buyerAddress,
Address sellerAddress, Address sellerAddress,
Address arbitratorAddress, Address arbitratorAddress,
boolean isBuyerOffererOrSellerTaker, boolean isBuyerOffererAndSellerTaker,
String offererAccountId, String offererAccountId,
String takerAccountId, String takerAccountId,
PaymentAccountContractData offererPaymentAccountContractData, PaymentAccountContractData offererPaymentAccountContractData,
@ -89,7 +87,7 @@ public class Contract implements Serializable {
this.tradeAmount = tradeAmount.value; this.tradeAmount = tradeAmount.value;
this.takeOfferFeeTxID = takeOfferFeeTxID; this.takeOfferFeeTxID = takeOfferFeeTxID;
this.arbitratorAddress = arbitratorAddress; this.arbitratorAddress = arbitratorAddress;
this.isBuyerOffererOrSellerTaker = isBuyerOffererOrSellerTaker; this.isBuyerOffererAndSellerTaker = isBuyerOffererAndSellerTaker;
this.offererAccountId = offererAccountId; this.offererAccountId = offererAccountId;
this.takerAccountId = takerAccountId; this.takerAccountId = takerAccountId;
this.offererPaymentAccountContractData = offererPaymentAccountContractData; this.offererPaymentAccountContractData = offererPaymentAccountContractData;
@ -103,44 +101,44 @@ public class Contract implements Serializable {
} }
public String getBuyerAccountId() { public String getBuyerAccountId() {
return isBuyerOffererOrSellerTaker ? offererAccountId : takerAccountId; return isBuyerOffererAndSellerTaker ? offererAccountId : takerAccountId;
} }
public String getSellerAccountId() { public String getSellerAccountId() {
return isBuyerOffererOrSellerTaker ? takerAccountId : offererAccountId; return isBuyerOffererAndSellerTaker ? takerAccountId : offererAccountId;
} }
public String getBuyerPayoutAddressString() { public String getBuyerPayoutAddressString() {
return isBuyerOffererOrSellerTaker ? offererPayoutAddressString : takerPayoutAddressString; return isBuyerOffererAndSellerTaker ? offererPayoutAddressString : takerPayoutAddressString;
} }
public String getSellerPayoutAddressString() { public String getSellerPayoutAddressString() {
return isBuyerOffererOrSellerTaker ? takerPayoutAddressString : offererPayoutAddressString; return isBuyerOffererAndSellerTaker ? takerPayoutAddressString : offererPayoutAddressString;
} }
public PubKeyRing getBuyerPubKeyRing() { public PubKeyRing getBuyerPubKeyRing() {
return isBuyerOffererOrSellerTaker ? offererPubKeyRing : takerPubKeyRing; return isBuyerOffererAndSellerTaker ? offererPubKeyRing : takerPubKeyRing;
} }
public PubKeyRing getSellerPubKeyRing() { public PubKeyRing getSellerPubKeyRing() {
return isBuyerOffererOrSellerTaker ? takerPubKeyRing : offererPubKeyRing; return isBuyerOffererAndSellerTaker ? takerPubKeyRing : offererPubKeyRing;
} }
public byte[] getBuyerBtcPubKey() { public byte[] getBuyerBtcPubKey() {
return isBuyerOffererOrSellerTaker ? offererBtcPubKey : takerBtcPubKey; return isBuyerOffererAndSellerTaker ? offererBtcPubKey : takerBtcPubKey;
} }
public byte[] getSellerBtcPubKey() { public byte[] getSellerBtcPubKey() {
return isBuyerOffererOrSellerTaker ? takerBtcPubKey : offererBtcPubKey; return isBuyerOffererAndSellerTaker ? takerBtcPubKey : offererBtcPubKey;
} }
public PaymentAccountContractData getBuyerPaymentAccountContractData() { public PaymentAccountContractData getBuyerPaymentAccountContractData() {
return isBuyerOffererOrSellerTaker ? offererPaymentAccountContractData : takerPaymentAccountContractData; return isBuyerOffererAndSellerTaker ? offererPaymentAccountContractData : takerPaymentAccountContractData;
} }
public PaymentAccountContractData getSellerPaymentAccountContractData() { public PaymentAccountContractData getSellerPaymentAccountContractData() {
return isBuyerOffererOrSellerTaker ? takerPaymentAccountContractData : offererPaymentAccountContractData; return isBuyerOffererAndSellerTaker ? takerPaymentAccountContractData : offererPaymentAccountContractData;
} }
public String getPaymentMethodName() { public String getPaymentMethodName() {
@ -166,17 +164,19 @@ public class Contract implements Serializable {
@Override @Override
public String toString() { public String toString() {
return "Contract{" + return "Contract{" +
"tac='" + tac + '\'' + "offer=" + offer +
", offer=" + offer +
", tradeAmount=" + tradeAmount + ", tradeAmount=" + tradeAmount +
", isBuyerOffererOrSellerTaker=" + isBuyerOffererOrSellerTaker +
", takeOfferFeeTxID='" + takeOfferFeeTxID + '\'' + ", takeOfferFeeTxID='" + takeOfferFeeTxID + '\'' +
", offererAccountID='" + offererAccountId + '\'' + ", arbitratorAddress=" + arbitratorAddress +
", takerAccountID='" + takerAccountId + '\'' + ", isBuyerOffererAndSellerTaker=" + isBuyerOffererAndSellerTaker +
", offererPaymentAccount=" + offererPaymentAccountContractData + ", offererAccountId='" + offererAccountId + '\'' +
", takerPaymentAccount=" + takerPaymentAccountContractData + ", takerAccountId='" + takerAccountId + '\'' +
", offererPaymentAccountContractData=" + offererPaymentAccountContractData +
", takerPaymentAccountContractData=" + takerPaymentAccountContractData +
", offererPubKeyRing=" + offererPubKeyRing + ", offererPubKeyRing=" + offererPubKeyRing +
", takerPubKeyRing=" + takerPubKeyRing + ", takerPubKeyRing=" + takerPubKeyRing +
", buyerAddress=" + buyerAddress +
", sellerAddress=" + sellerAddress +
", offererPayoutAddressString='" + offererPayoutAddressString + '\'' + ", offererPayoutAddressString='" + offererPayoutAddressString + '\'' +
", takerPayoutAddressString='" + takerPayoutAddressString + '\'' + ", takerPayoutAddressString='" + takerPayoutAddressString + '\'' +
", offererBtcPubKey=" + Arrays.toString(offererBtcPubKey) + ", offererBtcPubKey=" + Arrays.toString(offererBtcPubKey) +
@ -192,7 +192,7 @@ public class Contract implements Serializable {
Contract contract = (Contract) o; Contract contract = (Contract) o;
if (tradeAmount != contract.tradeAmount) return false; if (tradeAmount != contract.tradeAmount) return false;
if (isBuyerOffererOrSellerTaker != contract.isBuyerOffererOrSellerTaker) return false; if (isBuyerOffererAndSellerTaker != contract.isBuyerOffererAndSellerTaker) return false;
if (offer != null ? !offer.equals(contract.offer) : contract.offer != null) return false; if (offer != null ? !offer.equals(contract.offer) : contract.offer != null) return false;
if (takeOfferFeeTxID != null ? !takeOfferFeeTxID.equals(contract.takeOfferFeeTxID) : contract.takeOfferFeeTxID != null) if (takeOfferFeeTxID != null ? !takeOfferFeeTxID.equals(contract.takeOfferFeeTxID) : contract.takeOfferFeeTxID != null)
return false; return false;
@ -219,8 +219,7 @@ public class Contract implements Serializable {
if (takerPayoutAddressString != null ? !takerPayoutAddressString.equals(contract.takerPayoutAddressString) : contract.takerPayoutAddressString != null) if (takerPayoutAddressString != null ? !takerPayoutAddressString.equals(contract.takerPayoutAddressString) : contract.takerPayoutAddressString != null)
return false; return false;
if (!Arrays.equals(offererBtcPubKey, contract.offererBtcPubKey)) return false; if (!Arrays.equals(offererBtcPubKey, contract.offererBtcPubKey)) return false;
if (!Arrays.equals(takerBtcPubKey, contract.takerBtcPubKey)) return false; return Arrays.equals(takerBtcPubKey, contract.takerBtcPubKey);
return !(tac != null ? !tac.equals(contract.tac) : contract.tac != null);
} }
@ -230,7 +229,7 @@ public class Contract implements Serializable {
result = 31 * result + (int) (tradeAmount ^ (tradeAmount >>> 32)); result = 31 * result + (int) (tradeAmount ^ (tradeAmount >>> 32));
result = 31 * result + (takeOfferFeeTxID != null ? takeOfferFeeTxID.hashCode() : 0); result = 31 * result + (takeOfferFeeTxID != null ? takeOfferFeeTxID.hashCode() : 0);
result = 31 * result + (arbitratorAddress != null ? arbitratorAddress.hashCode() : 0); result = 31 * result + (arbitratorAddress != null ? arbitratorAddress.hashCode() : 0);
result = 31 * result + (isBuyerOffererOrSellerTaker ? 1 : 0); result = 31 * result + (isBuyerOffererAndSellerTaker ? 1 : 0);
result = 31 * result + (offererAccountId != null ? offererAccountId.hashCode() : 0); result = 31 * result + (offererAccountId != null ? offererAccountId.hashCode() : 0);
result = 31 * result + (takerAccountId != null ? takerAccountId.hashCode() : 0); result = 31 * result + (takerAccountId != null ? takerAccountId.hashCode() : 0);
result = 31 * result + (offererPaymentAccountContractData != null ? offererPaymentAccountContractData.hashCode() : 0); result = 31 * result + (offererPaymentAccountContractData != null ? offererPaymentAccountContractData.hashCode() : 0);
@ -243,7 +242,7 @@ public class Contract implements Serializable {
result = 31 * result + (takerPayoutAddressString != null ? takerPayoutAddressString.hashCode() : 0); result = 31 * result + (takerPayoutAddressString != null ? takerPayoutAddressString.hashCode() : 0);
result = 31 * result + (offererBtcPubKey != null ? Arrays.hashCode(offererBtcPubKey) : 0); result = 31 * result + (offererBtcPubKey != null ? Arrays.hashCode(offererBtcPubKey) : 0);
result = 31 * result + (takerBtcPubKey != null ? Arrays.hashCode(takerBtcPubKey) : 0); result = 31 * result + (takerBtcPubKey != null ? Arrays.hashCode(takerBtcPubKey) : 0);
result = 31 * result + (tac != null ? tac.hashCode() : 0);
return result; return result;
} }
} }

View file

@ -53,6 +53,10 @@ public final class Offer implements PubKeyProtectedExpirablePayload {
transient private static final Logger log = LoggerFactory.getLogger(Offer.class); transient private static final Logger log = LoggerFactory.getLogger(Offer.class);
public static final long TTL = 10 * 60 * 1000; // 10 min. public static final long TTL = 10 * 60 * 1000; // 10 min.
public final static String TAC_OFFERER = "When placing that offer I accept that anyone who fulfills my conditions can " +
"take that offer.";
public static final String TAC_TAKER = "With taking the offer I commit to the trade conditions as defined.";
public enum Direction {BUY, SELL} public enum Direction {BUY, SELL}
@ -397,14 +401,21 @@ public final class Offer implements PubKeyProtectedExpirablePayload {
", fiatPrice=" + fiatPrice + ", fiatPrice=" + fiatPrice +
", amount=" + amount + ", amount=" + amount +
", minAmount=" + minAmount + ", minAmount=" + minAmount +
", address=" + offererAddress + ", offererAddress=" + offererAddress +
", pubKeyRing.hashCode()=" + pubKeyRing.hashCode() + ", pubKeyRing=" + pubKeyRing +
", paymentMethodName='" + paymentMethodName + '\'' + ", paymentMethodName='" + paymentMethodName + '\'' +
", paymentMethodCountryCode='" + paymentMethodCountryCode + '\'' + ", paymentMethodCountryCode='" + paymentMethodCountryCode + '\'' +
", offererPaymentAccountId='" + offererPaymentAccountId + '\'' + ", offererPaymentAccountId='" + offererPaymentAccountId + '\'' +
", acceptedCountryCodes=" + acceptedCountryCodes + ", acceptedCountryCodes=" + acceptedCountryCodes +
", arbitratorAddresses=" + arbitratorAddresses + ", arbitratorAddresses=" + arbitratorAddresses +
", offerFeePaymentTxID='" + offerFeePaymentTxID + '\'' + ", offerFeePaymentTxID='" + offerFeePaymentTxID + '\'' +
", state=" + state +
", stateProperty=" + stateProperty +
", availabilityProtocol=" + availabilityProtocol +
", errorMessageProperty=" + errorMessageProperty +
", TAC_OFFERER=" + TAC_OFFERER +
", TAC_TAKER=" + TAC_TAKER +
'}'; '}';
} }
} }

View file

@ -41,10 +41,11 @@ public class SignAndPublishDepositTxAsBuyer extends TradeTask {
try { try {
runInterceptHook(); runInterceptHook();
log.debug("getContractAsJson"); log.info("\n\n------------------------------------------------------------\n"
log.debug("----------"); + "Contract as json\n"
log.debug(trade.getContractAsJson()); + trade.getContractAsJson()
log.debug("----------"); + "\n------------------------------------------------------------\n");
byte[] contractHash = Hash.getHash(trade.getContractAsJson()); byte[] contractHash = Hash.getHash(trade.getContractAsJson());
trade.setContractHash(contractHash); trade.setContractHash(contractHash);

View file

@ -48,11 +48,11 @@ public class CreateAndSignContract extends TradeTask {
TradingPeer taker = processModel.tradingPeer; TradingPeer taker = processModel.tradingPeer;
PaymentAccountContractData offererPaymentAccountContractData = processModel.getPaymentAccountContractData(trade); PaymentAccountContractData offererPaymentAccountContractData = processModel.getPaymentAccountContractData(trade);
PaymentAccountContractData takerPaymentAccountContractData = taker.getPaymentAccountContractData(); PaymentAccountContractData takerPaymentAccountContractData = taker.getPaymentAccountContractData();
boolean isBuyerOffererOrSellerTaker = trade instanceof BuyerAsOffererTrade; boolean isBuyerOffererAndSellerTaker = trade instanceof BuyerAsOffererTrade;
Address buyerAddress = isBuyerOffererOrSellerTaker ? processModel.getMyAddress() : processModel.getTempTradingPeerAddress(); Address buyerAddress = isBuyerOffererAndSellerTaker ? processModel.getMyAddress() : processModel.getTempTradingPeerAddress();
Address sellerAddress = isBuyerOffererOrSellerTaker ? processModel.getTempTradingPeerAddress() : processModel.getMyAddress(); Address sellerAddress = isBuyerOffererAndSellerTaker ? processModel.getTempTradingPeerAddress() : processModel.getMyAddress();
log.debug("isBuyerOffererOrSellerTaker " + isBuyerOffererOrSellerTaker); log.debug("isBuyerOffererAndSellerTaker " + isBuyerOffererAndSellerTaker);
log.debug("buyerAddress " + buyerAddress); log.debug("buyerAddress " + buyerAddress);
log.debug("sellerAddress " + sellerAddress); log.debug("sellerAddress " + sellerAddress);
Contract contract = new Contract( Contract contract = new Contract(
@ -62,7 +62,7 @@ public class CreateAndSignContract extends TradeTask {
buyerAddress, buyerAddress,
sellerAddress, sellerAddress,
trade.getArbitratorAddress(), trade.getArbitratorAddress(),
isBuyerOffererOrSellerTaker, isBuyerOffererAndSellerTaker,
processModel.getAccountId(), processModel.getAccountId(),
taker.getAccountId(), taker.getAccountId(),
offererPaymentAccountContractData, offererPaymentAccountContractData,

View file

@ -44,6 +44,11 @@ public class CreateAndSignDepositTxAsSeller extends TradeTask {
Coin sellerInputAmount = FeePolicy.SECURITY_DEPOSIT.add(FeePolicy.TX_FEE).add(trade.getTradeAmount()); Coin sellerInputAmount = FeePolicy.SECURITY_DEPOSIT.add(FeePolicy.TX_FEE).add(trade.getTradeAmount());
Coin msOutputAmount = sellerInputAmount.add(FeePolicy.SECURITY_DEPOSIT); Coin msOutputAmount = sellerInputAmount.add(FeePolicy.SECURITY_DEPOSIT);
log.info("\n\n------------------------------------------------------------\n"
+ "Contract as json\n"
+ trade.getContractAsJson()
+ "\n------------------------------------------------------------\n");
byte[] contractHash = Hash.getHash(trade.getContractAsJson()); byte[] contractHash = Hash.getHash(trade.getContractAsJson());
trade.setContractHash(contractHash); trade.setContractHash(contractHash);
PreparedDepositTxAndOffererInputs result = processModel.getTradeWalletService().offererCreatesAndSignsDepositTx( PreparedDepositTxAndOffererInputs result = processModel.getTradeWalletService().offererCreatesAndSignsDepositTx(

View file

@ -40,10 +40,10 @@ public class SignAndPublishDepositTxAsSeller extends TradeTask {
protected void run() { protected void run() {
try { try {
runInterceptHook(); runInterceptHook();
log.debug("getContractAsJson"); log.info("\n\n------------------------------------------------------------\n"
log.debug("----------"); + "Contract as json\n"
log.debug(trade.getContractAsJson()); + trade.getContractAsJson()
log.debug("----------"); + "\n------------------------------------------------------------\n");
byte[] contractHash = Hash.getHash(trade.getContractAsJson()); byte[] contractHash = Hash.getHash(trade.getContractAsJson());
trade.setContractHash(contractHash); trade.setContractHash(contractHash);

View file

@ -41,7 +41,7 @@ public class BroadcastTakeOfferFeeTx extends TradeTask {
new FutureCallback<Transaction>() { new FutureCallback<Transaction>() {
@Override @Override
public void onSuccess(Transaction transaction) { public void onSuccess(Transaction transaction) {
log.debug("Take offer fee published successfully. Transaction ID = " + transaction.getHashAsString()); log.debug("Trading fee published successfully. Transaction ID = " + transaction.getHashAsString());
trade.setState(Trade.State.TAKER_FEE_PAID); trade.setState(Trade.State.TAKER_FEE_PAID);
complete(); complete();
@ -49,7 +49,7 @@ public class BroadcastTakeOfferFeeTx extends TradeTask {
@Override @Override
public void onFailure(@NotNull Throwable t) { public void onFailure(@NotNull Throwable t) {
appendToErrorMessage("Take offer fee payment failed. Maybe your network connection was lost. Please try again."); appendToErrorMessage("Trading fee payment failed. Maybe your network connection was lost. Please try again.");
failed(t); failed(t);
} }
}); });

View file

@ -47,10 +47,10 @@ public class VerifyAndSignContract extends TradeTask {
PaymentAccountContractData offererPaymentAccountContractData = offerer.getPaymentAccountContractData(); PaymentAccountContractData offererPaymentAccountContractData = offerer.getPaymentAccountContractData();
PaymentAccountContractData takerPaymentAccountContractData = processModel.getPaymentAccountContractData(trade); PaymentAccountContractData takerPaymentAccountContractData = processModel.getPaymentAccountContractData(trade);
boolean isBuyerOffererOrSellerTaker = trade instanceof SellerAsTakerTrade; boolean isBuyerOffererAndSellerTaker = trade instanceof SellerAsTakerTrade;
Address buyerAddress = isBuyerOffererOrSellerTaker ? processModel.getTempTradingPeerAddress() : processModel.getMyAddress(); Address buyerAddress = isBuyerOffererAndSellerTaker ? processModel.getTempTradingPeerAddress() : processModel.getMyAddress();
Address sellerAddress = isBuyerOffererOrSellerTaker ? processModel.getMyAddress() : processModel.getTempTradingPeerAddress(); Address sellerAddress = isBuyerOffererAndSellerTaker ? processModel.getMyAddress() : processModel.getTempTradingPeerAddress();
log.debug("isBuyerOffererOrSellerTaker " + isBuyerOffererOrSellerTaker); log.debug("isBuyerOffererAndSellerTaker " + isBuyerOffererAndSellerTaker);
log.debug("buyerAddress " + buyerAddress); log.debug("buyerAddress " + buyerAddress);
log.debug("sellerAddress " + sellerAddress); log.debug("sellerAddress " + sellerAddress);
@ -61,7 +61,7 @@ public class VerifyAndSignContract extends TradeTask {
buyerAddress, buyerAddress,
sellerAddress, sellerAddress,
trade.getArbitratorAddress(), trade.getArbitratorAddress(),
isBuyerOffererOrSellerTaker, isBuyerOffererAndSellerTaker,
offerer.getAccountId(), offerer.getAccountId(),
processModel.getAccountId(), processModel.getAccountId(),
offererPaymentAccountContractData, offererPaymentAccountContractData,

View file

@ -67,7 +67,6 @@ public class User implements Serializable {
private Alert displayedAlert; private Alert displayedAlert;
@Nullable
private List<Arbitrator> acceptedArbitrators = new ArrayList<>(); private List<Arbitrator> acceptedArbitrators = new ArrayList<>();
@Nullable @Nullable
private Arbitrator registeredArbitrator; private Arbitrator registeredArbitrator;
@ -244,7 +243,6 @@ public class User implements Serializable {
return registeredArbitrator; return registeredArbitrator;
} }
@Nullable
public List<Arbitrator> getAcceptedArbitrators() { public List<Arbitrator> getAcceptedArbitrators() {
return acceptedArbitrators; return acceptedArbitrators;
} }

View file

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

View file

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

View file

@ -111,12 +111,16 @@ public abstract class PaymentMethodForm {
protected void addAllowedPeriod() { protected void addAllowedPeriod() {
long hours = paymentAccount.getPaymentMethod().getMaxTradePeriod() / 6; long hours = paymentAccount.getPaymentMethod().getMaxTradePeriod() / 6;
String displayText = hours + " hours"; String displayText = hours + " hours";
if (hours == 24) if (hours == 1)
displayText = "1 hour";
else if (hours == 24)
displayText = "1 day"; displayText = "1 day";
if (hours > 24) else if (hours > 24)
displayText = hours / 24 + " days"; 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(); abstract protected void autoFillNameTextField();

View file

@ -202,10 +202,16 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
log.debug("Wallet restored with seed words"); log.debug("Wallet restored with seed words");
new Popup() 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" + .information("Wallet restored successfully with the new seed words.\n\n" +
"You need to restart now the application.") "You need to restart now the application.")
.closeButtonText("Restart") .closeButtonText("Restart")
.onClose(() -> BitsquareApp.restartDownHandler.run()).show(); .onClose(() -> BitsquareApp.restartDownHandler.run()).show();*/
}), }),
throwable -> UserThread.execute(() -> { throwable -> UserThread.execute(() -> {
log.error(throwable.getMessage()); 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.offer.OfferView;
import io.bitsquare.gui.main.portfolio.PortfolioView; import io.bitsquare.gui.main.portfolio.PortfolioView;
import io.bitsquare.gui.main.portfolio.openoffer.OpenOffersView; 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.OfferDetailsPopup;
import io.bitsquare.gui.popups.Popup; import io.bitsquare.gui.popups.Popup;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
@ -226,9 +225,13 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
private void onShowFundsScreen() { private void onShowFundsScreen() {
if (!BitsquareApp.DEV_MODE) { if (!BitsquareApp.DEV_MODE) {
if (model.getDisplaySecurityDepositInfo()) { 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" + "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(); model.onSecurityDepositInfoDisplayed();
} }
@ -435,12 +438,16 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
UserThread.runAfter(() -> { UserThread.runAfter(() -> {
new Popup().headLine(BSResources.get("createOffer.success.headline")) new Popup().headLine(BSResources.get("createOffer.success.headline"))
.message(BSResources.get("createOffer.success.info")) .message(BSResources.get("createOffer.success.info"))
.onClose(() -> { .actionButtonText("Go to \"Open offers\"")
navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class); .onAction(() -> {
close(); close();
UserThread.runAfter(() ->
navigation.navigateTo(MainView.class, PortfolioView.class, OpenOffersView.class),
100, TimeUnit.MILLISECONDS);
}) })
.onClose(() -> close())
.show(); .show();
}, 300, TimeUnit.MILLISECONDS); }, 100, TimeUnit.MILLISECONDS);
} }
}; };
} }

View file

@ -289,7 +289,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
if (newValue != null) { if (newValue != null) {
if (offer.getState() == Offer.State.OFFER_FEE_PAID) if (offer.getState() == Offer.State.OFFER_FEE_PAID)
this.errorMessage.set(newValue + 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" + "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."); "Please try to restart you application and check your network connection to see if you can resolve the issue.");
else else

View file

@ -239,6 +239,19 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
private void onRemoveOpenOffer(Offer offer) { private void onRemoveOpenOffer(Offer offer) {
if (model.isAuthenticated()) { if (model.isAuthenticated()) {
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, model.onRemoveOpenOffer(offer,
() -> { () -> {
log.debug("Remove offer was successful"); log.debug("Remove offer was successful");
@ -249,11 +262,6 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
log.error(message); log.error(message);
new Popup().warning("Remove offer failed:\n" + message).show(); new Popup().warning("Remove offer failed:\n" + message).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 showWarning(String masthead, String message, Class target) { private void showWarning(String masthead, String message, Class target) {

View file

@ -127,6 +127,9 @@ class TakeOfferDataModel extends ActivatableDataModel {
void initWithData(Offer offer) { void initWithData(Offer offer) {
this.offer = offer; this.offer = offer;
addressEntry = walletService.getAddressEntryByOfferId(offer.getId());
checkNotNull(addressEntry, "addressEntry must not be null");
ObservableList<PaymentAccount> possiblePaymentAccounts = getPossiblePaymentAccounts(); ObservableList<PaymentAccount> possiblePaymentAccounts = getPossiblePaymentAccounts();
checkArgument(!possiblePaymentAccounts.isEmpty(), "possiblePaymentAccounts.isEmpty()"); checkArgument(!possiblePaymentAccounts.isEmpty(), "possiblePaymentAccounts.isEmpty()");
paymentAccount = possiblePaymentAccounts.get(0); paymentAccount = possiblePaymentAccounts.get(0);
@ -136,9 +139,6 @@ class TakeOfferDataModel extends ActivatableDataModel {
calculateVolume(); calculateVolume();
calculateTotalToPay(); calculateTotalToPay();
addressEntry = walletService.getAddressEntryByOfferId(offer.getId());
checkNotNull(addressEntry, "addressEntry must not be null");
balanceListener = new BalanceListener(addressEntry.getAddress()) { balanceListener = new BalanceListener(addressEntry.getAddress()) {
@Override @Override
public void onBalanceChanged(@NotNull Coin balance) { public void onBalanceChanged(@NotNull Coin balance) {
@ -255,6 +255,8 @@ class TakeOfferDataModel extends ActivatableDataModel {
amountAsCoin.get() != null && amountAsCoin.get() != null &&
!amountAsCoin.get().isZero()) { !amountAsCoin.get().isZero()) {
volumeAsFiat.set(new ExchangeRate(offer.getPrice()).coinToFiat(amountAsCoin.get())); 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) { if (newValue && model.getTrade() != null && model.getTrade().errorMessageProperty().get() == null) {
UserThread.runAfter(() -> { UserThread.runAfter(() -> {
new Popup().information(BSResources.get("takeOffer.success.info")) new Popup().information(BSResources.get("takeOffer.success.info"))
.onClose(() -> { .actionButtonText("Go to \"Open trades\"")
navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class); .onAction(() -> {
close(); close();
UserThread.runAfter(() ->
navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class),
100, TimeUnit.MILLISECONDS);
}) })
.onClose(() -> close())
.show(); .show();
}, 300, TimeUnit.MILLISECONDS); }, 100, TimeUnit.MILLISECONDS);
} }
}); });
@ -322,7 +326,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
private void onTakeOffer() { private void onTakeOffer() {
Offer offer = model.getOffer(); Offer offer = model.getOffer();
if (model.getShowTakeOfferConfirmation()) { if (model.getShowTakeOfferConfirmation()) {
offerDetailsPopup.onTakeOffer(() -> model.onTakeOffer()).show(offer); offerDetailsPopup.onTakeOffer(() -> model.onTakeOffer()).show(offer, model.dataModel.amountAsCoin.get());
} else { } else {
if (model.hasAcceptedArbitrators()) { if (model.hasAcceptedArbitrators()) {
model.onTakeOffer(); model.onTakeOffer();
@ -351,9 +355,13 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
Dialog.Actions.CLOSE.handle(actionEvent); 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" + "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(); 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."; "Please try to restart you application and check your network connection to see if you can resolve the issue.";
break; break;
case TAKER_FEE_PAID: 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" + "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."; "Please try to restart you application and check your network connection to see if you can resolve the issue.";
break; break;

View file

@ -72,8 +72,21 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
table.setItems(model.getList()); table.setItems(model.getList());
} }
private void onCancelOpenOffer(OpenOffer openOffer) { private void onRemoveOpenOffer(OpenOffer openOffer) {
if (model.isAuthenticated()) { if (model.isAuthenticated()) {
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, model.onCancelOpenOffer(openOffer,
() -> { () -> {
log.debug("Remove offer was successful"); log.debug("Remove offer was successful");
@ -85,10 +98,6 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
log.error(message); log.error(message);
new Popup().warning("Remove offer failed:\n" + message).show(); new Popup().warning("Remove offer failed:\n" + message).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 openOfferDetails(OpenOfferListItem item) { /* private void openOfferDetails(OpenOfferListItem item) {
@ -284,7 +293,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null) { if (item != null) {
button.setOnAction(event -> onCancelOpenOffer(item.getOpenOffer())); button.setOnAction(event -> onRemoveOpenOffer(item.getOpenOffer()));
setGraphic(button); setGraphic(button);
} else { } else {
setGraphic(null); setGraphic(null);

View file

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

View file

@ -60,9 +60,11 @@ public class CompletedView extends TradeStepDetailsView {
@Override @Override
public void doActivate() { public void doActivate() {
super.doActivate(); super.doActivate();
withdrawAddressTextField.focusedProperty().addListener(focusedPropertyListener);
withdrawAddressTextField.setValidator(model.getBtcAddressValidator()); // TODO valid. handler need improvement
withdrawButton.disableProperty().bind(model.getWithdrawalButtonDisable()); //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 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 // 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 @Override
public void doDeactivate() { public void doDeactivate() {
super.doDeactivate(); super.doDeactivate();
withdrawAddressTextField.focusedProperty().removeListener(focusedPropertyListener); //withdrawAddressTextField.focusedProperty().removeListener(focusedPropertyListener);
withdrawButton.disableProperty().unbind(); // withdrawButton.disableProperty().unbind();
} }

View file

@ -111,12 +111,25 @@ public class ConfirmPaymentReceivedView extends TradeStepDetailsView {
Preferences preferences = model.dataModel.getPreferences(); Preferences preferences = model.dataModel.getPreferences();
String key = PopupId.PAYMENT_RECEIVED; String key = PopupId.PAYMENT_RECEIVED;
if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE) { if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE) {
new Popup().information("Please note that as soon you have confirmed that you have received the " + new Popup().headLine("Confirmation")
"payment the locked Bitcoin will be released.\n" + .message("Do you have received the payment from your trading partner?\n\n" +
"There is no way to reverse a Bitcoin payment. Confirm only if you are sure.") "Please note that as soon you have confirmed the locked Bitcoin will be released.\n" +
.onClose(() -> preferences.dontShowAgain(key)) "There is no way to reverse a Bitcoin payment.")
.dontShowAgainId(key, preferences)
.actionButtonText("Yes I have received the payment")
.closeButtonText("No")
.onAction(() -> confirmPaymentReceived())
.show(); .show();
} else { } else {
confirmPaymentReceived();
}
} 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 confirmPaymentReceived() {
confirmFiatReceivedButton.setDisable(true); confirmFiatReceivedButton.setDisable(true);
statusProgressIndicator.setVisible(true); statusProgressIndicator.setVisible(true);
@ -125,11 +138,6 @@ public class ConfirmPaymentReceivedView extends TradeStepDetailsView {
model.fiatPaymentReceived(); model.fiatPaymentReceived();
} }
} 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();
}
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -143,11 +143,23 @@ public class StartPaymentView extends TradeStepDetailsView {
if (model.isAuthenticated()) { if (model.isAuthenticated()) {
String key = PopupId.PAYMENT_SENT; String key = PopupId.PAYMENT_SENT;
if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE) { if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE) {
new Popup().information("You are confirming that you have transferred the payment to your trading partner.\n" + new Popup().headLine("Confirmation")
"Please click the \"Payment started\" button only if you have completed the transfer.") .message("Do you have transferred the payment to your trading partner?")
.onClose(() -> preferences.dontShowAgain(key)) .dontShowAgainId(key, preferences)
.actionButtonText("Yes I have started the payment")
.closeButtonText("No")
.onAction(() -> confirmPaymentStarted())
.show(); .show();
} else { } else {
confirmPaymentStarted();
}
} 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 confirmPaymentStarted() {
paymentStartedButton.setDisable(true); paymentStartedButton.setDisable(true);
statusProgressIndicator.setVisible(true); statusProgressIndicator.setVisible(true);
@ -156,11 +168,6 @@ public class StartPaymentView extends TradeStepDetailsView {
model.fiatPaymentStarted(); model.fiatPaymentStarted();
} }
} 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();
}
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -52,7 +52,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
btcDenominationComboBox = addLabelComboBox(root, gridRow, "Bitcoin denomination:", Layout.FIRST_ROW_DISTANCE).second; btcDenominationComboBox = addLabelComboBox(root, gridRow, "Bitcoin denomination:", Layout.FIRST_ROW_DISTANCE).second;
blockExplorerComboBox = addLabelComboBox(root, ++gridRow, "Bitcoin block explorer:").second; blockExplorerComboBox = addLabelComboBox(root, ++gridRow, "Bitcoin block explorer:").second;
useAnimationsCheckBox = addLabelCheckBox(root, ++gridRow, "Use animations:", "").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; showPlaceOfferConfirmationCheckBox = addLabelCheckBox(root, ++gridRow, "Show confirmation at place offer:", "").second;
showTakeOfferConfirmationCheckBox = addLabelCheckBox(root, ++gridRow, "Show confirmation at take offer:", "").second; showTakeOfferConfirmationCheckBox = addLabelCheckBox(root, ++gridRow, "Show confirmation at take offer:", "").second;
autoSelectArbitratorsCheckBox = addLabelCheckBox(root, ++gridRow, "Auto select arbitrators by language:", "").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() { private void onSelectNetwork() {
if (netWorkComboBox.getSelectionModel().getSelectedItem() != preferences.getBitcoinNetwork()) { if (netWorkComboBox.getSelectionModel().getSelectedItem() != preferences.getBitcoinNetwork()) {
if (netWorkComboBox.getSelectionModel().getSelectedItem() == BitcoinNetwork.MAINNET) { if (netWorkComboBox.getSelectionModel().getSelectedItem() == BitcoinNetwork.MAINNET) {
new Popup().warning("The application is under heavy development. " + new Popup().warning("The application needs more tested before it can be used in mainnet.\n" +
"Using the mainnet network with Bitcoin is not recommended at that stage.\n\n" + "Please follow our mailing list to get informed when Bitsquare will be ready for mainnet.")
"Are you sure you want to switch to mainnet?")
.onAction(() -> selectNetwork())
.onClose(() -> UserThread.execute(() -> netWorkComboBox.getSelectionModel().select(preferences.getBitcoinNetwork()))) .onClose(() -> UserThread.execute(() -> netWorkComboBox.getSelectionModel().select(preferences.getBitcoinNetwork())))
.show(); .show();
} else { } else {
@ -166,10 +164,14 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
} }
private void selectNetwork() { private void selectNetwork() {
//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()); preferences.setBitcoinNetwork(netWorkComboBox.getSelectionModel().getSelectedItem());
new Popup().warning("You need to restart the application to apply the change of the Bitcoin network..\n\n" + UserThread.runAfter(() -> BitsquareApp.shutDownHandler.run(), 1);
"Do you want to restart now?") })
.onAction(() -> BitsquareApp.restartDownHandler.run()) .onClose(() -> netWorkComboBox.getSelectionModel().select(preferences.getBitcoinNetwork()))
.show(); .show();
} }
} }

View file

@ -109,8 +109,7 @@ public class ContractPopup extends Popup {
Layout.FIRST_ROW_DISTANCE).second.setMouseTransparent(false); Layout.FIRST_ROW_DISTANCE).second.setMouseTransparent(false);
addLabelTextField(gridPane, ++rowIndex, "Offer date:", formatter.formatDateTime(offer.getDate())); addLabelTextField(gridPane, ++rowIndex, "Offer date:", formatter.formatDateTime(offer.getDate()));
addLabelTextField(gridPane, ++rowIndex, "Trade date:", formatter.formatDateTime(dispute.getTradeDate())); 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:", formatter.getDirectionDescription(offer.getDirection()));
addLabelTextField(gridPane, ++rowIndex, "Trade type:", direction);
addLabelTextField(gridPane, ++rowIndex, "Price:", formatter.formatFiat(offer.getPrice()) + " " + offer.getCurrencyCode()); addLabelTextField(gridPane, ++rowIndex, "Price:", formatter.formatFiat(offer.getPrice()) + " " + offer.getCurrencyCode());
addLabelTextField(gridPane, ++rowIndex, "Trade amount:", formatter.formatCoinWithCode(contract.getTradeAmount())); addLabelTextField(gridPane, ++rowIndex, "Trade amount:", formatter.formatCoinWithCode(contract.getTradeAmount()));
addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "Buyer bitcoin address:", 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, "Buyer Bitsquare account ID:", contract.getBuyerAccountId()).second.setMouseTransparent(false);
//addLabelTextField(gridPane, ++rowIndex, "Seller Bitsquare account ID:", contract.getSellerAccountId()).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, "Offer fee transaction ID:", offer.getOfferFeePaymentTxID());
addLabelTxIdTextField(gridPane, ++rowIndex, "Take offer fee transaction ID:", contract.takeOfferFeeTxID); addLabelTxIdTextField(gridPane, ++rowIndex, "Trading fee transaction ID:", contract.takeOfferFeeTxID);
if (dispute.getDepositTxSerialized() != null) if (dispute.getDepositTxSerialized() != null)
addLabelTxIdTextField(gridPane, ++rowIndex, "Deposit transaction ID:", dispute.getDepositTxId()); addLabelTxIdTextField(gridPane, ++rowIndex, "Deposit transaction ID:", dispute.getDepositTxId());
if (dispute.getPayoutTxSerialized() != null) if (dispute.getPayoutTxSerialized() != null)

View file

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

View file

@ -35,6 +35,8 @@ import javafx.scene.control.Button;
import javafx.scene.control.CheckBox; import javafx.scene.control.CheckBox;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip; import javafx.scene.control.Tooltip;
import org.bitcoinj.core.Coin;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -52,6 +54,7 @@ public class OfferDetailsPopup extends Popup {
private User user; private User user;
private final Navigation navigation; private final Navigation navigation;
private Offer offer; private Offer offer;
private Coin tradeAmount;
private Optional<Consumer<Offer>> placeOfferHandlerOptional = Optional.empty(); private Optional<Consumer<Offer>> placeOfferHandlerOptional = Optional.empty();
private Optional<Runnable> takeOfferHandlerOptional = Optional.empty(); private Optional<Runnable> takeOfferHandlerOptional = Optional.empty();
@ -68,6 +71,18 @@ public class OfferDetailsPopup extends Popup {
this.navigation = navigation; 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) { public OfferDetailsPopup show(Offer offer) {
this.offer = offer; this.offer = offer;
@ -110,25 +125,36 @@ public class OfferDetailsPopup extends Popup {
} }
private void addContent() { 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) if (offer.getPaymentMethodCountryCode() != null)
rows++; rows++;
if (offer.getOfferFeePaymentTxID() != null) if (offer.getOfferFeePaymentTxID() != null)
rows++; rows++;
if (offer.getAcceptedCountryCodes() != null) if (offer.getAcceptedCountryCodes() != null)
rows++; rows++;
if (placeOfferHandlerOptional.isPresent()) /* if (placeOfferHandlerOptional.isPresent())
rows -= 2; rows -= 2;*/
addTitledGroupBg(gridPane, ++rowIndex, rows, "Offer details"); addTitledGroupBg(gridPane, ++rowIndex, rows, "Details", Layout.GROUP_DISTANCE);
addLabelTextField(gridPane, rowIndex, "Offer ID:", offer.getId(), Layout.FIRST_ROW_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, "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) if (offer.getPaymentMethodCountryCode() != null)
addLabelTextField(gridPane, ++rowIndex, "Offerers country of bank:", offer.getPaymentMethodCountryCode()); addLabelTextField(gridPane, ++rowIndex, "Offerers country of bank:", offer.getPaymentMethodCountryCode());
if (offer.getAcceptedCountryCodes() != null) { if (offer.getAcceptedCountryCodes() != null) {
@ -141,41 +167,48 @@ public class OfferDetailsPopup extends Popup {
tooltip = new Tooltip(CountryUtil.getNamesByCodesString(offer.getAcceptedCountryCodes())); tooltip = new Tooltip(CountryUtil.getNamesByCodesString(offer.getAcceptedCountryCodes()));
} }
TextField acceptedCountries = addLabelTextField(gridPane, ++rowIndex, "Accepted taker countries:", countries).second; 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())); addLabelTextField(gridPane, ++rowIndex, "Accepted arbitrators:", formatter.arbitratorAddressesToString(offer.getArbitratorAddresses()));
if (offer.getOfferFeePaymentTxID() != null) 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()) { if (placeOfferHandlerOptional.isPresent()) {
Tuple2<Button, Button> tuple = add2ButtonsAfterGroup(gridPane, ++rowIndex, "Confirm place offer", "Cancel"); addTitledGroupBg(gridPane, ++rowIndex, 1, "Commitment", Layout.GROUP_DISTANCE);
Button placeButton = tuple.first; addLabelTextField(gridPane, rowIndex, "Please note:", Offer.TAC_OFFERER, Layout.FIRST_ROW_AND_GROUP_DISTANCE);
placeButton.setOnAction(e -> {
if (user.getAcceptedArbitrators().size() > 0) { Button cancelButton = addConfirmButton(true);
placeOfferHandlerOptional.get().accept(offer); addCancelButton(cancelButton, true);
} else if (takeOfferHandlerOptional.isPresent()) {
addTitledGroupBg(gridPane, ++rowIndex, 1, "Contract", Layout.GROUP_DISTANCE);
addLabelTextField(gridPane, rowIndex, "Terms and conditions:", Offer.TAC_TAKER, Layout.FIRST_ROW_AND_GROUP_DISTANCE);
Button cancelButton = addConfirmButton(false);
addCancelButton(cancelButton, false);
} else { } else {
new Popup().warning("You have no arbitrator selected.\n" + Button cancelButton = addButtonAfterGroup(gridPane, ++rowIndex, "Close");
"Please select at least one arbitrator.").show();
navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class, ArbitratorSelectionView.class);
}
hide();
});
Button cancelButton = tuple.second;
cancelButton.setOnAction(e -> { cancelButton.setOnAction(e -> {
closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run()); closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run());
hide(); hide();
}); });
}
}
CheckBox checkBox = addCheckBox(gridPane, ++rowIndex, "Don't show again", 5); @NotNull
checkBox.setSelected(!preferences.getShowPlaceOfferConfirmation()); private Button addConfirmButton(boolean isPlaceOffer) {
checkBox.setOnAction(e -> preferences.setShowPlaceOfferConfirmation(!checkBox.isSelected())); Tuple2<Button, Button> tuple = add2ButtonsAfterGroup(gridPane,
} else if (takeOfferHandlerOptional.isPresent()) { ++rowIndex,
Tuple2<Button, Button> tuple = add2ButtonsAfterGroup(gridPane, ++rowIndex, "Confirm take offer", "Cancel"); isPlaceOffer ? "Confirm place offer" : "Confirm take offer",
"Cancel");
Button placeButton = tuple.first; Button placeButton = tuple.first;
placeButton.setOnAction(e -> { placeButton.setOnAction(e -> {
if (user.getAcceptedArbitrators().size() > 0) { if (user.getAcceptedArbitrators().size() > 0) {
if (isPlaceOffer)
placeOfferHandlerOptional.get().accept(offer);
else
takeOfferHandlerOptional.get().run(); takeOfferHandlerOptional.get().run();
} else { } else {
new Popup().warning("You have no arbitrator selected.\n" + new Popup().warning("You have no arbitrator selected.\n" +
@ -185,23 +218,22 @@ public class OfferDetailsPopup extends Popup {
} }
hide(); hide();
}); });
return tuple.second;
}
Button cancelButton = tuple.second; private void addCancelButton(Button cancelButton, boolean isPlaceOffer) {
cancelButton.setOnAction(e -> { cancelButton.setOnAction(e -> {
closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run()); closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run());
hide(); hide();
}); });
CheckBox checkBox = addCheckBox(gridPane, ++rowIndex, "Don't show again", 5); CheckBox checkBox = addCheckBox(gridPane, ++rowIndex, "Don't show again", 5);
checkBox.setPadding(new Insets(20, 0, 25, 0)); if (isPlaceOffer) {
checkBox.setSelected(!preferences.getShowPlaceOfferConfirmation());
checkBox.setOnAction(e -> preferences.setShowPlaceOfferConfirmation(!checkBox.isSelected()));
} else {
checkBox.setSelected(!preferences.getShowTakeOfferConfirmation()); checkBox.setSelected(!preferences.getShowTakeOfferConfirmation());
checkBox.setOnAction(e -> preferences.setShowTakeOfferConfirmation(!checkBox.isSelected())); checkBox.setOnAction(e -> preferences.setShowTakeOfferConfirmation(!checkBox.isSelected()));
} else {
Button cancelButton = addButtonAfterGroup(gridPane, ++rowIndex, "Close");
cancelButton.setOnAction(e -> {
closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run());
hide();
});
} }
} }
} }

View file

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

View file

@ -90,7 +90,15 @@ public class TradeDetailsPopup extends Popup {
Offer offer = trade.getOffer(); Offer offer = trade.getOffer();
Contract contract = trade.getContract(); 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 buyerPaymentAccountContractData = null;
PaymentAccountContractData sellerPaymentAccountContractData = null; PaymentAccountContractData sellerPaymentAccountContractData = null;
@ -98,6 +106,8 @@ public class TradeDetailsPopup extends Popup {
rows++; rows++;
if (contract != null) { if (contract != null) {
rows++;
buyerPaymentAccountContractData = contract.getBuyerPaymentAccountContractData(); buyerPaymentAccountContractData = contract.getBuyerPaymentAccountContractData();
sellerPaymentAccountContractData = contract.getSellerPaymentAccountContractData(); sellerPaymentAccountContractData = contract.getSellerPaymentAccountContractData();
if (buyerPaymentAccountContractData != null) if (buyerPaymentAccountContractData != null)
@ -120,13 +130,9 @@ public class TradeDetailsPopup extends Popup {
if (trade.errorMessageProperty().get() != null) if (trade.errorMessageProperty().get() != null)
rows += 2; rows += 2;
addTitledGroupBg(gridPane, ++rowIndex, rows, "Trade details"); addTitledGroupBg(gridPane, ++rowIndex, rows, "Details", Layout.GROUP_DISTANCE);
addLabelTextField(gridPane, rowIndex, "Trade ID:", trade.getId(), Layout.FIRST_ROW_DISTANCE); addLabelTextField(gridPane, rowIndex, "Trade ID:", trade.getId(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
addLabelTextField(gridPane, ++rowIndex, "Trade date:", formatter.formatDateTime(trade.getDate())); 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()); addLabelTextField(gridPane, ++rowIndex, "Selected arbitrator:", trade.getArbitratorAddress().getFullAddress());
if (contract != null) { if (contract != null) {
@ -144,15 +150,22 @@ public class TradeDetailsPopup extends Popup {
addLabelTextField(gridPane, ++rowIndex, "Payment method:", BSResources.get(contract.getPaymentMethodName())); 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) 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) if (trade.getDepositTx() != null)
addLabelTxIdTextField(gridPane, ++rowIndex, "Deposit transaction ID:", trade.getDepositTx().getHashAsString()); addLabelTxIdTextField(gridPane, ++rowIndex, "Deposit transaction ID:", trade.getDepositTx().getHashAsString());
if (trade.getPayoutTx() != null) if (trade.getPayoutTx() != null)
addLabelTxIdTextField(gridPane, ++rowIndex, "Payout transaction ID:", trade.getPayoutTx().getHashAsString()); 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) { if (trade.errorMessageProperty().get() != null) {
TextArea textArea = addLabelTextArea(gridPane, ++rowIndex, "Error message:", "").second; TextArea textArea = addLabelTextArea(gridPane, ++rowIndex, "Error message:", "").second;
textArea.setText(trade.errorMessageProperty().get()); textArea.setText(trade.errorMessageProperty().get());
@ -169,26 +182,6 @@ public class TradeDetailsPopup extends Popup {
TextField state = addLabelTextField(gridPane, ++rowIndex, "Trade state:").second; TextField state = addLabelTextField(gridPane, ++rowIndex, "Trade state:").second;
state.setText(trade.getState().getPhase().name()); 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"); Button cancelButton = addButtonAfterGroup(gridPane, ++rowIndex, "Close");

View file

@ -125,8 +125,7 @@ public class BSFormatter {
log.warn("Exception at formatBtc: " + t.toString()); log.warn("Exception at formatBtc: " + t.toString());
return ""; return "";
} }
} } else {
else {
return ""; return "";
} }
} }
@ -141,8 +140,7 @@ public class BSFormatter {
log.warn("Exception at formatBtcWithCode: " + t.toString()); log.warn("Exception at formatBtcWithCode: " + t.toString());
return ""; return "";
} }
} } else {
else {
return ""; return "";
} }
} }
@ -155,8 +153,7 @@ public class BSFormatter {
log.warn("Exception at parseToBtc: " + t.toString()); log.warn("Exception at parseToBtc: " + t.toString());
return Coin.ZERO; return Coin.ZERO;
} }
} } else {
else {
return Coin.ZERO; return Coin.ZERO;
} }
} }
@ -208,8 +205,7 @@ public class BSFormatter {
log.warn("Exception at formatFiat: " + t.toString()); log.warn("Exception at formatFiat: " + t.toString());
return ""; return "";
} }
} } else {
else {
return ""; return "";
} }
} }
@ -223,8 +219,7 @@ public class BSFormatter {
log.warn("Exception at formatFiatWithCode: " + t.toString()); log.warn("Exception at formatFiatWithCode: " + t.toString());
return ""; return "";
} }
} } else {
else {
return ""; return "";
} }
} }
@ -238,8 +233,7 @@ public class BSFormatter {
return Fiat.valueOf(currencyCode, 0); return Fiat.valueOf(currencyCode, 0);
} }
} } else {
else {
return Fiat.valueOf(currencyCode, 0); return Fiat.valueOf(currencyCode, 0);
} }
} }
@ -374,4 +368,8 @@ public class BSFormatter {
return ""; 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. 2. The user is responsible to use the software in compliance with local laws.
<br/><br/> <br/><br/>
3. The user confirms that he has read and agreed to the rules defined in our 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/> process.<br/>
</body> </body>
</html> </html>

View file

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

View file

@ -646,16 +646,32 @@ public class PeerGroup implements MessageListener, ConnectionListener {
// Reported peers // Reported peers
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
void addToReportedPeers(HashSet<ReportedPeer> reportedPeers, Connection connection) { void addToReportedPeers(HashSet<ReportedPeer> newReportedPeers, Connection connection) {
Log.traceCall(); Log.traceCall();
// we disconnect misbehaving nodes trying to send too many peers // we disconnect misbehaving nodes trying to send too many peers
// reported peers include the peers connected peers which is normally max. 8 but we give some headroom // reported peers include the peers connected peers which is normally max. 8 but we give some headroom
// for safety // for safety
if (reportedPeers.size() > 1100) { if (newReportedPeers.size() > 1100) {
connection.shutDown(); connection.shutDown();
} else { } else {
reportedPeers.remove(new ReportedPeer(getMyAddress(), new Date())); newReportedPeers.remove(new ReportedPeer(getMyAddress(), new Date()));
this.reportedPeers.addAll(reportedPeers);
//TODO if we have already peer, we mix date from old and new item
//
/* Map<Address, ReportedPeer> reportedPeersMap = new HashMap<>();
reportedPeers.stream().forEach(e -> reportedPeersMap.put(e.address, e));
HashSet<ReportedPeer> newAdjustedReportedPeers = new HashSet<>();
newReportedPeers.stream()
.forEach(e -> {
if()
long adjustedTime = (e.lastActivityDate.getTime() +
reportedPeersMap.get(e.address).lastActivityDate.getTime()) / 2;
newAdjustedReportedPeers.add(new ReportedPeer(e.address,
new Date(adjustedTime)));
});*/
this.reportedPeers.addAll(newReportedPeers);
purgeReportedPeersIfExceeds(); purgeReportedPeersIfExceeds();
} }
@ -670,6 +686,8 @@ public class PeerGroup implements MessageListener, ConnectionListener {
"We remove random peers from the reported peers list.", MAX_REPORTED_PEERS, size); "We remove random peers from the reported peers list.", MAX_REPORTED_PEERS, size);
int diff = size - MAX_REPORTED_PEERS; int diff = size - MAX_REPORTED_PEERS;
List<ReportedPeer> list = new LinkedList<>(getReportedNotConnectedPeerAddresses()); List<ReportedPeer> list = new LinkedList<>(getReportedNotConnectedPeerAddresses());
//TODO sort and remove oldest
for (int i = 0; i < diff; i++) { for (int i = 0; i < diff; i++) {
ReportedPeer toRemove = getAndRemoveRandomReportedPeer(list); ReportedPeer toRemove = getAndRemoveRandomReportedPeer(list);
reportedPeers.remove(toRemove); reportedPeers.remove(toRemove);