Merge branch 'master' into Development

# Conflicts:
#	common/pom.xml
#	common/src/main/java/io/bitsquare/app/Version.java
#	core/pom.xml
#	core/src/main/java/io/bitsquare/locale/CurrencyUtil.java
#	gui/pom.xml
#	jsocks/pom.xml
#	jtorctl/pom.xml
#	jtorproxy/pom.xml
#	network/pom.xml
#	package/linux/create_32bit_app.sh
#	package/linux/create_64bit_app.sh
#	package/mac/create_app.sh
#	package/windows/Bitsquare.iss
#	package/windows/create_32bit_app.bat
#	package/windows/create_app.bat
#	pom.xml
#	seednode/pom.xml
This commit is contained in:
Manfred Karrer 2016-05-05 13:30:18 +02:00
commit b9dfa0a7a7
53 changed files with 530 additions and 251 deletions

View file

@ -54,7 +54,6 @@ import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Font;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
@ -100,10 +99,12 @@ public class BitsquareApp extends Application {
@Override
public void start(Stage primaryStage) throws IOException {
String logPath = Paths.get(env.getProperty(BitsquareEnvironment.APP_DATA_DIR_KEY), "bitsquare").toString();
Log.setup(logPath, !IS_RELEASE_VERSION);
log.info("Log files under: " + logPath);
Log.setup(logPath);
log.info("Log files under: " + logPath);
Version.printVersion();
Utilities.printSysInfo();
Log.setLevel(!IS_RELEASE_VERSION);
UserThread.setExecutor(Platform::runLater);
UserThread.setTimerClass(UITimer.class);
@ -124,6 +125,8 @@ public class BitsquareApp extends Application {
Thread.setDefaultUncaughtExceptionHandler(handler);
Thread.currentThread().setUncaughtExceptionHandler(handler);
if (Utilities.isRestrictedCryptography())
Utilities.removeCryptographyRestrictions();
Security.addProvider(new BouncyCastleProvider());
BitsquareApp.primaryStage = primaryStage;
@ -158,7 +161,7 @@ public class BitsquareApp extends Application {
mainView.setPersistedFilesCorrupted(corruptedDatabaseFiles);
});*/
scene = new Scene(mainView.getRoot(), 1150, 740);
scene = new Scene(mainView.getRoot(), 1190, 740);
scene.getStylesheets().setAll(
"/io/bitsquare/gui/bitsquare.css",
"/io/bitsquare/gui/images.css");
@ -190,7 +193,7 @@ public class BitsquareApp extends Application {
// configure the primary stage
primaryStage.setTitle(env.getRequiredProperty(APP_NAME_KEY));
primaryStage.setScene(scene);
primaryStage.setMinWidth(1130);
primaryStage.setMinWidth(1170);
primaryStage.setMinHeight(620);
// on windows the title icon is also used as task bar icon in a larger size
@ -208,10 +211,18 @@ public class BitsquareApp extends Application {
// make the UI visible
primaryStage.show();
Font fon = Font.getDefault();
Font fonds = Font.getDefault();
//showDebugWindow();
if (!Utilities.isCorrectOSArchitecture()) {
String osArchitecture = Utilities.getOSArchitecture();
// We don't force a shutdown as the osArchitecture might in strange cases return a wrong value.
// Needs at least more testing on different machines...
new Popup<>().warning("You have probably the wrong version installed for the architecture of your computer.\n" +
"Your computers architecture is: " + osArchitecture + ".\n" +
"The Bitsquare binary you installed is: " + Utilities.getJVMArchitecture() + ".\n" +
"Please shut down and re-install the correct version (" + osArchitecture + ").")
.show();
}
} catch (Throwable throwable) {
showErrorPopup(throwable, false);
}
@ -220,8 +231,8 @@ public class BitsquareApp extends Application {
private void showSendAlertMessagePopup() {
AlertManager alertManager = injector.getInstance(AlertManager.class);
new SendAlertMessageWindow()
.onAddAlertMessage((alert, privKeyString) -> alertManager.addAlertMessageIfKeyIsValid(alert, privKeyString))
.onRemoveAlertMessage(privKeyString -> alertManager.removeAlertMessageIfKeyIsValid(privKeyString))
.onAddAlertMessage(alertManager::addAlertMessageIfKeyIsValid)
.onRemoveAlertMessage(alertManager::removeAlertMessageIfKeyIsValid)
.show();
}

View file

@ -128,7 +128,7 @@ public class SystemTray {
e1.printStackTrace();
}
});
exitItem.addActionListener(e -> onExit.run());
exitItem.addActionListener(e -> UserThread.execute(onExit::run));
}
public void hideStage() {

View file

@ -152,7 +152,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
return type != null ? "Market price (" + type.name + ")" : "";
},
model.marketPriceCurrency, model.typeProperty));
HBox.setMargin(marketPriceBox.third, new Insets(0, 20, 0, 0));
HBox.setMargin(marketPriceBox.third, new Insets(0, 0, 0, 0));
Tuple2<TextField, VBox> availableBalanceBox = getBalanceBox("Available balance");
@ -243,7 +243,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
private Tuple2<TextField, VBox> getBalanceBox(String text) {
TextField textField = new TextField();
textField.setEditable(false);
textField.setPrefWidth(120);
textField.setPrefWidth(140);
textField.setMouseTransparent(true);
textField.setFocusTraversable(false);
textField.setStyle("-fx-alignment: center; -fx-background-color: white;");

View file

@ -81,6 +81,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.security.Security;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@ -443,6 +444,7 @@ public class MainViewModel implements ViewModel {
walletPasswordWindow
.onAesKey(aesKey -> {
tradeWalletService.setAesKey(aesKey);
walletService.setAesKey(aesKey);
walletInitialized.set(true);
})
.hideCloseButton()
@ -541,7 +543,7 @@ public class MainViewModel implements ViewModel {
log.error(msg);
UserThread.execute(() -> new Popup<>().warning(msg)
.actionButtonText("Shut down")
.onAction(() -> BitsquareApp.shutDownHandler.run())
.onAction(BitsquareApp.shutDownHandler::run)
.closeButtonText("Report bug at Github issues")
.onClose(() -> Utilities.openWebPage("https://github.com/bitsquare/bitsquare/issues"))
.show());
@ -549,6 +551,15 @@ public class MainViewModel implements ViewModel {
}
};
checkCryptoThread.start();
if (Security.getProvider("BC") == null) {
new Popup<>().warning("There is a problem with the crypto libraries. BountyCastle is not available.")
.actionButtonText("Shut down")
.onAction(BitsquareApp.shutDownHandler::run)
.closeButtonText("Report bug at Github issues")
.onClose(() -> Utilities.openWebPage("https://github.com/bitsquare/bitsquare/issues"))
.show();
}
}
@ -813,11 +824,10 @@ public class MainViewModel implements ViewModel {
private void displayAlertIfPresent(Alert alert) {
boolean alreadyDisplayed = alert != null && alert.equals(user.getDisplayedAlert());
user.setDisplayedAlert(alert);
if (alert != null && !alreadyDisplayed) {
if (!alert.isUpdateInfo || !alert.version.equals(Version.VERSION))
new DisplayAlertMessageWindow().alertMessage(alert).show();
}
if (alert != null &&
!alreadyDisplayed &&
(!alert.isUpdateInfo || alert.isNewVersion()))
new DisplayAlertMessageWindow().alertMessage(alert).show();
}
private void swapPendingOfferFundingEntries() {

View file

@ -87,6 +87,7 @@ public class BackupView extends ActivatableView<GridPane, Void> {
protected void activate() {
selectBackupDir.setOnAction(e -> {
DirectoryChooser directoryChooser = new DirectoryChooser();
directoryChooser.setInitialDirectory(new File(System.getProperty("user.home")));
directoryChooser.setTitle("Select backup location");
File dir = directoryChooser.showDialog(stage);
if (dir != null) {

View file

@ -117,6 +117,7 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
if (wallet.checkAESKey(aesKey)) {
wallet.decrypt(aesKey);
tradeWalletService.setAesKey(null);
walletService.setAesKey(null);
new Popup()
.feedback("Wallet successfully decrypted and password protection removed.")
.show();
@ -133,6 +134,7 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
wallet.encrypt(keyCrypterScrypt, aesKey);
// we save the key for the trade wallet as we don't require passwords here
tradeWalletService.setAesKey(aesKey);
walletService.setAesKey(aesKey);
new Popup()
.feedback("Wallet successfully encrypted and password protection enabled.")
.show();

View file

@ -292,7 +292,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
private Coin getAmountAsCoin() {
Coin senderAmount = formatter.parseToCoin(amountTextField.getText());
if (!Restrictions.isAboveFixedTxFeeAndDust(senderAmount)) {
if (!Restrictions.isAboveFixedTxFeeForTradesAndDust(senderAmount)) {
senderAmount = Coin.ZERO;
/* new Popup()
.warning("The amount is lower than the transaction fee and the min. possible tx value (dust).")

View file

@ -43,7 +43,7 @@ public class TransactionsListItem {
@Nullable
private Tradable tradable;
private String details;
private String addressString;
private String addressString = "";
private String direction;
private TxConfidenceListener txConfidenceListener;
private boolean received;

View file

@ -41,17 +41,21 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
import org.bitcoinj.core.*;
import org.bitcoinj.script.Script;
import javax.inject.Inject;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -77,7 +81,8 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
private final DisputeManager disputeManager;
private final OfferDetailsWindow offerDetailsWindow;
private WalletEventListener walletEventListener;
private EventHandler<KeyEvent> keyEventEventHandler;
private Scene scene;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, lifecycle
@ -164,6 +169,33 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
updateList();
}
};
keyEventEventHandler = event -> {
if (new KeyCodeCombination(KeyCode.A, KeyCombination.SHORTCUT_DOWN).match(event)) {
Map<Long, List<Coin>> map = new HashMap<>();
observableList.stream().forEach(item -> {
Coin amountAsCoin = item.getAmountAsCoin();
List<Coin> list;
long key = amountAsCoin.getValue();
if (!map.containsKey(key)) {
list = new ArrayList<>();
map.put(key, list);
} else {
list = map.get(key);
}
list.add(amountAsCoin);
});
StringBuilder stringBuilder = new StringBuilder();
map.entrySet().stream().forEach(e -> {
stringBuilder.append("Nr. of transactions for amount ").
append(formatter.formatCoinWithCode(Coin.valueOf(e.getKey()))).
append(": ").
append(e.getValue().size()).
append("\n");
});
new Popup().headLine("Statistical info").information(stringBuilder.toString()).show();
}
};
}
@Override
@ -173,6 +205,10 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
updateList();
walletService.getWallet().addEventListener(walletEventListener);
scene = root.getScene();
if (scene != null)
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
}
@Override
@ -180,6 +216,9 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
sortedList.comparatorProperty().unbind();
observableList.forEach(TransactionsListItem::cleanup);
walletService.getWallet().removeEventListener(walletEventListener);
if (scene != null)
scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
}

View file

@ -22,7 +22,6 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.app.BitsquareApp;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.AddressEntryException;
import io.bitsquare.btc.Restrictions;
import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.common.UserThread;
@ -40,8 +39,10 @@ import io.bitsquare.trade.TradeManager;
import io.bitsquare.trade.closed.ClosedTradableManager;
import io.bitsquare.trade.failed.FailedTradesManager;
import io.bitsquare.user.Preferences;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
@ -50,10 +51,7 @@ import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
import org.apache.commons.lang3.StringUtils;
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.*;
import org.jetbrains.annotations.NotNull;
import org.spongycastle.crypto.params.KeyParameter;
@ -87,6 +85,10 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
private Set<WithdrawalListItem> selectedItems = new HashSet<>();
private BalanceListener balanceListener;
private Set<String> fromAddresses;
private Coin amountOfSelectedItems = Coin.ZERO;
private ObjectProperty<Coin> senderAmountAsCoinProperty = new SimpleObjectProperty<>(Coin.ZERO);
private ChangeListener<String> amountListener;
private ChangeListener<Boolean> amountFocusListener;
///////////////////////////////////////////////////////////////////////////////////////////
@ -130,6 +132,23 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
updateList();
}
};
amountListener = (observable, oldValue, newValue) -> {
if (amountTextField.focusedProperty().get()) {
try {
senderAmountAsCoinProperty.set(formatter.parseToCoin(amountTextField.getText()));
} catch (Throwable t) {
log.error("Error at amountTextField input. " + t.toString());
}
}
};
amountFocusListener = (observable, oldValue, newValue) -> {
if (oldValue && !newValue) {
if (senderAmountAsCoinProperty.get().isPositive())
amountTextField.setText(formatter.formatCoin(senderAmountAsCoinProperty.get()));
else
amountTextField.setText("");
}
};
}
@Override
@ -140,17 +159,18 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
reset();
amountTextField.textProperty().addListener(amountListener);
amountTextField.focusedProperty().addListener(amountFocusListener);
walletService.addBalanceListener(balanceListener);
withdrawButton.disableProperty().bind(Bindings.createBooleanBinding(() -> !areInputsValid(),
amountTextField.textProperty(), withdrawToTextField.textProperty()));
}
@Override
protected void deactivate() {
sortedList.comparatorProperty().unbind();
observableList.forEach(WithdrawalListItem::cleanup);
withdrawButton.disableProperty().unbind();
walletService.removeBalanceListener(balanceListener);
amountTextField.textProperty().removeListener(amountListener);
amountTextField.focusedProperty().removeListener(amountFocusListener);
}
@ -160,8 +180,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
@FXML
public void onWithdraw() {
Coin senderAmount = formatter.parseToCoin(amountTextField.getText());
if (Restrictions.isAboveFixedTxFeeAndDust(senderAmount)) {
if (areInputsValid()) {
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
@Override
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
@ -186,33 +205,38 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
}
};
try {
// We need to use the max. amount (amountOfSelectedItems) as the senderAmount might be less then
// we have available and then the fee calculation would return 0
// TODO Get a proper fee calculation from BitcoinJ directly
Coin requiredFee = walletService.getRequiredFeeForMultipleAddresses(fromAddresses,
withdrawToTextField.getText(), senderAmount);
Coin receiverAmount = senderAmount.subtract(requiredFee);
if (BitsquareApp.DEV_MODE) {
doWithdraw(receiverAmount, callback);
} else {
new Popup().headLine("Confirm withdrawal request")
.confirmation("Sending: " + formatter.formatCoinWithCode(senderAmount) + "\n" +
"From address: " + withdrawFromTextField.getText() + "\n" +
"To receiving address: " + withdrawToTextField.getText() + ".\n" +
"Required transaction fee is: " + formatter.formatCoinWithCode(requiredFee) + "\n\n" +
"The recipient will receive: " + formatter.formatCoinWithCode(receiverAmount) + "\n\n" +
"Are you sure you want to withdraw that amount?")
.actionButtonText("Yes")
.onAction(() -> doWithdraw(receiverAmount, callback))
.closeButtonText("Cancel")
.show();
withdrawToTextField.getText(), amountOfSelectedItems);
Coin receiverAmount = senderAmountAsCoinProperty.get().subtract(requiredFee);
if (receiverAmount.isPositive()) {
if (BitsquareApp.DEV_MODE) {
doWithdraw(receiverAmount, callback);
} else {
new Popup().headLine("Confirm withdrawal request")
.confirmation("Sending: " + formatter.formatCoinWithCode(senderAmountAsCoinProperty.get()) + "\n" +
"From address: " + withdrawFromTextField.getText() + "\n" +
"To receiving address: " + withdrawToTextField.getText() + ".\n" +
"Required transaction fee is: " + formatter.formatCoinWithCode(requiredFee) + "\n\n" +
"The recipient will receive: " + formatter.formatCoinWithCode(receiverAmount) + "\n\n" +
"Are you sure you want to withdraw that amount?")
.actionButtonText("Yes")
.onAction(() -> doWithdraw(receiverAmount, callback))
.closeButtonText("Cancel")
.show();
}
} else {
new Popup().warning("The amount you would like to send is too low as the bitcoin transaction fee will be deducted.\n" +
"Please use a higher amount.").show();
}
} catch (Throwable e) {
e.printStackTrace();
log.error(e.getMessage());
new Popup().error(e.getMessage()).show();
new Popup().warning(e.getMessage()).show();
}
} else {
new Popup().warning("The amount to transfer is lower than the transaction fee and the min. possible tx value (dust).")
.show();
}
}
@ -227,10 +251,13 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
.collect(Collectors.toSet());
if (!selectedItems.isEmpty()) {
Coin sum = Coin.valueOf(selectedItems.stream().mapToLong(e -> e.getBalance().getValue()).sum());
if (sum.isPositive()) {
amountTextField.setText(formatter.formatCoin(sum));
amountOfSelectedItems = Coin.valueOf(selectedItems.stream().mapToLong(e -> e.getBalance().getValue()).sum());
if (amountOfSelectedItems.isPositive()) {
senderAmountAsCoinProperty.set(amountOfSelectedItems);
amountTextField.setText(formatter.formatCoin(amountOfSelectedItems));
} else {
senderAmountAsCoinProperty.set(Coin.ZERO);
amountOfSelectedItems = Coin.ZERO;
amountTextField.setText("");
withdrawFromTextField.setText("");
}
@ -298,11 +325,17 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
updateList();
} catch (AddressFormatException e) {
new Popup().warning("The address is not correct. Please check the address format.").show();
} catch (Wallet.DustySendRequested e) {
new Popup().warning("The amount you would like to send is below the dust limit and would be rejected by the bitcoin network.\n" +
"Please use a higher amount.").show();
} catch (AddressEntryException e) {
new Popup().error(e.getMessage()).show();
} catch (InsufficientMoneyException e) {
log.warn(e.getMessage());
new Popup().warning("You don't have enough fund in your wallet.").show();
} catch (Throwable e) {
log.warn(e.getMessage());
new Popup().warning(e.getMessage()).show();
}
}
@ -315,6 +348,8 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
withdrawFromTextField.setPromptText("Select a source address from the table");
withdrawFromTextField.setTooltip(null);
amountOfSelectedItems = Coin.ZERO;
senderAmountAsCoinProperty.set(Coin.ZERO);
amountTextField.setText("");
amountTextField.setPromptText("Set the amount to withdraw");
@ -338,9 +373,27 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
}
private boolean areInputsValid() {
return btcAddressValidator.validate(withdrawToTextField.getText()).isValid &&
amountTextField.getText().length() > 0 &&
Restrictions.isAboveFixedTxFeeAndDust(formatter.parseToCoin(amountTextField.getText()));
if (!senderAmountAsCoinProperty.get().isPositive()) {
new Popup().warning("Please fill in a valid value for the amount to send (max. 8 decimal places).").show();
return false;
}
if (!btcAddressValidator.validate(withdrawToTextField.getText()).isValid) {
new Popup().warning("Please fill in a valid receiver bitcoin address.").show();
return false;
}
if (!amountOfSelectedItems.isPositive()) {
new Popup().warning("You need to select a source address in the table above.").show();
return false;
}
if (senderAmountAsCoinProperty.get().compareTo(amountOfSelectedItems) > 0) {
new Popup().warning("Your amount exceeds the available amount for the selected address.\n" +
"Consider to select multiple addresses in the table above if you want to withdraw more.").show();
return false;
}
return true;
}

View file

@ -27,10 +27,7 @@ import io.bitsquare.gui.main.offer.BuyOfferView;
import io.bitsquare.gui.main.offer.SellOfferView;
import io.bitsquare.gui.main.offer.offerbook.OfferBookListItem;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.locale.BSResources;
import io.bitsquare.locale.CryptoCurrency;
import io.bitsquare.locale.FiatCurrency;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.locale.*;
import io.bitsquare.trade.offer.Offer;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleStringProperty;
@ -69,6 +66,8 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
private Subscription tradeCurrencySubscriber;
private final StringProperty priceColumnLabel = new SimpleStringProperty();
private final StringProperty volumeColumnLabel = new SimpleStringProperty();
private Button buyOfferButton;
private Button sellOfferButton;
///////////////////////////////////////////////////////////////////////////////////////////
@ -120,6 +119,8 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
Tuple3<TableView<Offer>, VBox, Button> tupleSell = getOfferTable(Offer.Direction.SELL);
buyOfferTableView = tupleBuy.first;
sellOfferTableView = tupleSell.first;
buyOfferButton = tupleBuy.third;
sellOfferButton = tupleSell.third;
HBox hBox = new HBox();
hBox.setSpacing(30);
@ -135,19 +136,29 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
currencyComboBox.getSelectionModel().select(model.getTradeCurrency());
currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 25));
currencyComboBox.setOnAction(e -> {
model.onSetTradeCurrency(currencyComboBox.getSelectionModel().getSelectedItem());
TradeCurrency tradeCurrency = currencyComboBox.getSelectionModel().getSelectedItem();
model.onSetTradeCurrency(tradeCurrency);
updateChartData();
});
model.getOfferBookListItems().addListener(changeListener);
tradeCurrencySubscriber = EasyBind.subscribe(model.tradeCurrency,
newValue -> {
String code = newValue.getCode();
areaChart.setTitle("Offer book for " + newValue.getName());
tradeCurrency -> {
String code = tradeCurrency.getCode();
String tradeCurrencyName = tradeCurrency.getName();
areaChart.setTitle("Offer book for " + tradeCurrencyName);
priceColumnLabel.set("Price (" + code + "/BTC)");
volumeColumnLabel.set("Volume (" + code + ")");
xAxis.setLabel(priceColumnLabel.get());
xAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(xAxis, "", ""));
if (CurrencyUtil.isCryptoCurrency(code)) {
buyOfferButton.setText("I want to sell bitcoin / buy " + tradeCurrencyName);
sellOfferButton.setText("I want to buy bitcoin / sell " + tradeCurrencyName);
} else {
buyOfferButton.setText("I want to sell bitcoin");
sellOfferButton.setText("I want to buy bitcoin");
}
});
buyOfferTableView.setItems(model.getTop3BuyOfferList());
@ -316,7 +327,7 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
placeholder.setWrapText(true);
tableView.setPlaceholder(placeholder);
Label titleLabel = new Label(direction.equals(Offer.Direction.BUY) ? "Top 3 offers for buying bitcoin (bid)" : "Top 3 offers for selling bitcoin (ask)");
Label titleLabel = new Label(direction.equals(Offer.Direction.BUY) ? "Top 3 bid offers" : "Top 3 ask offers");
titleLabel.setStyle("-fx-font-weight: bold; -fx-font-size: 16; -fx-alignment: center");
UserThread.execute(() -> titleLabel.prefWidthProperty().bind(tableView.widthProperty()));
@ -355,10 +366,10 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis, "", ""));
seriesBuy = new XYChart.Series();
seriesBuy.setName("Offers for buying bitcoin ");
seriesBuy.setName("Bid offers ");
seriesSell = new XYChart.Series();
seriesSell.setName("Offers for selling bitcoin ");
seriesSell.setName("Ask offers");
areaChart = new AreaChart<>(xAxis, yAxis);
areaChart.setAnimated(false);

View file

@ -889,8 +889,9 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
cancelButton2 = addButton(gridPane, ++gridRow, BSResources.get("shared.cancel"));
cancelButton2.setOnAction(e -> {
if (model.dataModel.isWalletFunded.get()) {
new Popup().warning("You have already paid in the funds.\n" +
"Are you sure you want to cancel.")
new Popup().warning("You have already paid the funds.\n" +
"If you cancel now, your funds will be available immediately.\n" +
"Are you sure you want to cancel?")
.closeButtonText("No")
.actionButtonText("Yes, cancel")
.onAction(() -> {

View file

@ -493,9 +493,9 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
calculateVolume();
// handle minAmount/amount relationship
if (!dataModel.isMinAmountLessOrEqualAmount())
if (!dataModel.isMinAmountLessOrEqualAmount())
minAmount.set(amount.get());
else
else
amountValidationResult.set(result);
if (minAmount.get() != null)
@ -750,10 +750,11 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
boolean inputDataValid = isBtcInputValid(amount.get()).isValid &&
isBtcInputValid(minAmount.get()).isValid &&
isFiatInputValid(price.get()).isValid &&
dataModel.priceAsFiat.get() != null &&
dataModel.priceAsFiat.get().getValue() != 0 &&
isFiatInputValid(volume.get()).isValid &&
dataModel.isMinAmountLessOrEqualAmount() &&
!dataModel.useMarketBasedPrice.get() || dataModel.getMarketPriceMargin() != 0 &&
dataModel.useMarketBasedPrice.get() || (dataModel.priceAsFiat.get() != null && dataModel.priceAsFiat.get().getValue() != 0);
dataModel.isMinAmountLessOrEqualAmount();
isNextButtonDisabled.set(!inputDataValid);
// boolean notSufficientFees = dataModel.isWalletFunded.get() && dataModel.isMainNet.get() && !dataModel.isFeeFromFundingTxSufficient.get();
//isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || notSufficientFees);

View file

@ -272,7 +272,8 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
String postFix = selectedTradeCurrency instanceof FiatCurrency || model.showAllTradeCurrenciesProperty.get() ? "" :
" (" + mirroredDirectionText + " " + selectedTradeCurrency.getName() + ")";
offerBookTitle.setText("Offers for " + directionText + " bitcoin" + postFix);
// offerBookTitle.setText("Offers for " + directionText + " bitcoin" + postFix);
offerBookTitle.setText("Available offers");
createOfferButton.setText("Create new offer for " + directionText + " bitcoin" + postFix);
}

View file

@ -778,8 +778,9 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
cancelButton2 = addButton(gridPane, ++gridRow, BSResources.get("shared.cancel"));
cancelButton2.setOnAction(e -> {
if (model.dataModel.isWalletFunded.get()) {
new Popup().warning("You have already paid in the funds.\n" +
"Are you sure you want to cancel.")
new Popup().warning("You have already paid the funds.\n" +
"If you cancel now, your funds will be available immediately.\n" +
"Are you sure you want to cancel?")
.closeButtonText("No")
.actionButtonText("Yes, cancel")
.onAction(() -> {

View file

@ -31,7 +31,7 @@ public class TacWindow extends Overlay<TacWindow> {
"arising from, out of or in connection with the software or the use or other dealings in the software.\n\n" +
"2. The user is responsible to use the software in compliance with local laws. Don't use Bitsquare if the usage of Bitcoin is not legal in your jurisdiction.\n\n" +
"3. Bitcoin market price is delivered by 3rd parties (BitcoinAverage, Poloniex). It is your responsibility to double check the price with other sources.\n\n" +
"4. The user confirms that he has read and agreed to the rules regrading the dispute process:\n" +
"4. The user confirms that he has read and agreed to the rules regarding the dispute process:\n" +
" - You must finalize trades within the maximum duration specified for each payment method.\n" +
" - You must enter the trade ID in the \"reason for payment\" text field when doing the fiat payment transfer.\n" +
" - If the bank of the fiat sender charges fees the sender (bitcoin buyer) has to cover the fees.\n" +

View file

@ -183,7 +183,7 @@ public class BuyerStep5View extends TradeStepView {
} else {
if (toAddresses.isEmpty()) {
validateWithdrawAddress();
} else if (Restrictions.isAboveFixedTxFeeAndDust(senderAmount)) {
} else if (Restrictions.isAboveFixedTxFeeForTradesAndDust(senderAmount)) {
if (BitsquareApp.DEV_MODE) {
doWithdrawal(receiverAmount);

View file

@ -36,7 +36,6 @@ import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.GridPane;
import org.apache.commons.lang3.StringUtils;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription;
@ -152,13 +151,11 @@ public class SellerStep3View extends TradeStepView {
}
}
TextFieldWithCopyIcon myPaymentDetailsTextField = addLabelTextFieldWithCopyIcon(gridPane, ++gridRow,
myTitle, StringUtils.abbreviate(myPaymentDetails, 56)).second;
TextFieldWithCopyIcon myPaymentDetailsTextField = addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, myTitle, myPaymentDetails).second;
myPaymentDetailsTextField.setMouseTransparent(false);
myPaymentDetailsTextField.setTooltip(new Tooltip(myPaymentDetails));
TextFieldWithCopyIcon peersPaymentDetailsTextField = addLabelTextFieldWithCopyIcon(gridPane, ++gridRow,
peersTitle, StringUtils.abbreviate(peersPaymentDetails, 56)).second;
TextFieldWithCopyIcon peersPaymentDetailsTextField = addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, peersTitle, peersPaymentDetails).second;
peersPaymentDetailsTextField.setMouseTransparent(false);
peersPaymentDetailsTextField.setTooltip(new Tooltip(peersPaymentDetails));

View file

@ -74,7 +74,7 @@
<PropertyValueFactory property="onionAddress"/>
</cellValueFactory>
</TableColumn>
<TableColumn text="In/Out" fx:id="connectionTypeColumn" minWidth="70" maxWidth="80">
<TableColumn text="In/Out" fx:id="connectionTypeColumn" minWidth="80" maxWidth="90">
<cellValueFactory>
<PropertyValueFactory property="connectionType"/>
</cellValueFactory>

View file

@ -53,7 +53,7 @@ public class BSFormatter {
// Input of a group separator (1,123,45) lead to an validation error.
// Note: BtcFormat was intended to be used, but it lead to many problems (automatic format to mBit,
// no way to remove grouping separator). It seems to be not optimal for user input formatting.
private MonetaryFormat coinFormat = MonetaryFormat.BTC.repeatOptionalDecimals(2, 2);
private MonetaryFormat coinFormat = MonetaryFormat.BTC.minDecimals(2).repeatOptionalDecimals(1, 6);
// private String currencyCode = CurrencyUtil.getDefaultFiatCurrencyAsCode();
@ -97,7 +97,7 @@ public class BSFormatter {
if (useMilliBit)
return MonetaryFormat.MBTC;
else
return MonetaryFormat.BTC.repeatOptionalDecimals(2, 2);
return MonetaryFormat.BTC.minDecimals(2).repeatOptionalDecimals(1, 6);
}
/* public void setFiatCurrencyCode(String currencyCode) {