mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-06-24 23:00:36 -04:00
Add fee check to take offer, display spinner and txt, cleanup eventhandlers, hide support tickets tab for arbitr. if not arbitr.
This commit is contained in:
parent
eefafab977
commit
2d7aecd2ed
41 changed files with 583 additions and 286 deletions
|
@ -44,6 +44,8 @@ import java.util.concurrent.*;
|
||||||
public class Utilities {
|
public class Utilities {
|
||||||
private static final Logger log = LoggerFactory.getLogger(Utilities.class);
|
private static final Logger log = LoggerFactory.getLogger(Utilities.class);
|
||||||
private static long lastTimeStamp = System.currentTimeMillis();
|
private static long lastTimeStamp = System.currentTimeMillis();
|
||||||
|
public static final String LB = System.getProperty("line.separator");
|
||||||
|
public static final String LB2 = LB + LB;
|
||||||
|
|
||||||
public static String objectToJson(Object object) {
|
public static String objectToJson(Object object) {
|
||||||
Gson gson = new GsonBuilder()
|
Gson gson = new GsonBuilder()
|
||||||
|
|
|
@ -284,27 +284,24 @@ public class WalletService {
|
||||||
// Listener
|
// Listener
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public AddressConfidenceListener addAddressConfidenceListener(AddressConfidenceListener listener) {
|
public void addAddressConfidenceListener(AddressConfidenceListener listener) {
|
||||||
addressConfidenceListeners.add(listener);
|
addressConfidenceListeners.add(listener);
|
||||||
return listener;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeAddressConfidenceListener(AddressConfidenceListener listener) {
|
public void removeAddressConfidenceListener(AddressConfidenceListener listener) {
|
||||||
addressConfidenceListeners.remove(listener);
|
addressConfidenceListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TxConfidenceListener addTxConfidenceListener(TxConfidenceListener listener) {
|
public void addTxConfidenceListener(TxConfidenceListener listener) {
|
||||||
txConfidenceListeners.add(listener);
|
txConfidenceListeners.add(listener);
|
||||||
return listener;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeTxConfidenceListener(TxConfidenceListener listener) {
|
public void removeTxConfidenceListener(TxConfidenceListener listener) {
|
||||||
txConfidenceListeners.remove(listener);
|
txConfidenceListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BalanceListener addBalanceListener(BalanceListener listener) {
|
public void addBalanceListener(BalanceListener listener) {
|
||||||
balanceListeners.add(listener);
|
balanceListeners.add(listener);
|
||||||
return listener;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeBalanceListener(BalanceListener listener) {
|
public void removeBalanceListener(BalanceListener listener) {
|
||||||
|
@ -667,12 +664,12 @@ public class WalletService {
|
||||||
private class BitsquareWalletEventListener extends AbstractWalletEventListener {
|
private class BitsquareWalletEventListener extends AbstractWalletEventListener {
|
||||||
@Override
|
@Override
|
||||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||||
notifyBalanceListeners();
|
notifyBalanceListeners(tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||||
notifyBalanceListeners();
|
notifyBalanceListeners(tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -691,7 +688,7 @@ public class WalletService {
|
||||||
txConfidenceListener.onTransactionConfidenceChanged(tx.getConfidence()));
|
txConfidenceListener.onTransactionConfidenceChanged(tx.getConfidence()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyBalanceListeners() {
|
private void notifyBalanceListeners(Transaction tx) {
|
||||||
for (BalanceListener balanceListener : balanceListeners) {
|
for (BalanceListener balanceListener : balanceListeners) {
|
||||||
Coin balance;
|
Coin balance;
|
||||||
if (balanceListener.getAddress() != null)
|
if (balanceListener.getAddress() != null)
|
||||||
|
@ -699,7 +696,7 @@ public class WalletService {
|
||||||
else
|
else
|
||||||
balance = getAvailableBalance();
|
balance = getAvailableBalance();
|
||||||
|
|
||||||
balanceListener.onBalanceChanged(balance);
|
balanceListener.onBalanceChanged(balance, tx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package io.bitsquare.btc.listeners;
|
||||||
|
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.core.Transaction;
|
||||||
|
|
||||||
public class BalanceListener {
|
public class BalanceListener {
|
||||||
private Address address;
|
private Address address;
|
||||||
|
@ -35,6 +36,6 @@ public class BalanceListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("UnusedParameters")
|
@SuppressWarnings("UnusedParameters")
|
||||||
public void onBalanceChanged(Coin balance) {
|
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,6 +26,7 @@ import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
|
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
import org.fxmisc.easybind.Subscription;
|
import org.fxmisc.easybind.Subscription;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -51,12 +52,12 @@ public class SetupDepositBalanceListener extends TradeTask {
|
||||||
|
|
||||||
WalletService walletService = processModel.getWalletService();
|
WalletService walletService = processModel.getWalletService();
|
||||||
Address address = walletService.getAddressEntryByOfferId(trade.getId()).getAddress();
|
Address address = walletService.getAddressEntryByOfferId(trade.getId()).getAddress();
|
||||||
balanceListener = walletService.addBalanceListener(new BalanceListener(address) {
|
balanceListener = new BalanceListener(address) {
|
||||||
@Override
|
@Override
|
||||||
public void onBalanceChanged(Coin balance) {
|
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||||
updateBalance(balance);
|
updateBalance(balance);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
walletService.addBalanceListener(balanceListener);
|
walletService.addBalanceListener(balanceListener);
|
||||||
|
|
||||||
tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), newValue -> {
|
tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), newValue -> {
|
||||||
|
|
|
@ -153,7 +153,7 @@ public class BitsquareApp extends Application {
|
||||||
mainView.setPersistedFilesCorrupted(corruptedDatabaseFiles);
|
mainView.setPersistedFilesCorrupted(corruptedDatabaseFiles);
|
||||||
});*/
|
});*/
|
||||||
|
|
||||||
scene = new Scene(mainView.getRoot(), 1100, 740);
|
scene = new Scene(mainView.getRoot(), 1060, 740);
|
||||||
scene.getStylesheets().setAll(
|
scene.getStylesheets().setAll(
|
||||||
"/io/bitsquare/gui/bitsquare.css",
|
"/io/bitsquare/gui/bitsquare.css",
|
||||||
"/io/bitsquare/gui/images.css");
|
"/io/bitsquare/gui/images.css");
|
||||||
|
|
|
@ -36,7 +36,6 @@ bg color of non edit textFields: fafafa
|
||||||
-bs-red-soft: derive(-bs-error-red, 60%);
|
-bs-red-soft: derive(-bs-error-red, 60%);
|
||||||
-bs-orange: #dd8f05;
|
-bs-orange: #dd8f05;
|
||||||
|
|
||||||
|
|
||||||
-bs-blue-transparent: #0f87c344;
|
-bs-blue-transparent: #0f87c344;
|
||||||
-bs-green-transparent: #00aa3344;
|
-bs-green-transparent: #00aa3344;
|
||||||
|
|
||||||
|
@ -678,10 +677,6 @@ textfield */
|
||||||
-fx-background-color: -bs-content-bg-grey;
|
-fx-background-color: -bs-content-bg-grey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* TitledGroupBg */
|
/* TitledGroupBg */
|
||||||
#titled-group-bg-label {
|
#titled-group-bg-label {
|
||||||
-fx-font-weight: bold;
|
-fx-font-weight: bold;
|
||||||
|
@ -876,3 +871,22 @@ textfield */
|
||||||
-fx-font-size: 16;
|
-fx-font-size: 16;
|
||||||
-fx-alignment: center;
|
-fx-alignment: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************************
|
||||||
|
*
|
||||||
|
* Popups
|
||||||
|
*
|
||||||
|
********************************************************************************************************************/
|
||||||
|
|
||||||
|
#popup-headline {
|
||||||
|
-fx-font-size: 18;
|
||||||
|
-fx-text-fill: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
#popup-message {
|
||||||
|
-fx-font-size: 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
#popup-button {
|
||||||
|
-fx-font-size: 15;
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.core.Transaction;
|
||||||
|
|
||||||
public class BalanceTextField extends AnchorPane {
|
public class BalanceTextField extends AnchorPane {
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ public class BalanceTextField extends AnchorPane {
|
||||||
|
|
||||||
balanceListener = new BalanceListener(address) {
|
balanceListener = new BalanceListener(address) {
|
||||||
@Override
|
@Override
|
||||||
public void onBalanceChanged(Coin balance) {
|
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||||
updateBalance(balance);
|
updateBalance(balance);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -72,7 +73,7 @@ public class BalanceTextField extends AnchorPane {
|
||||||
updateBalance(walletService.getBalanceForAddress(address));
|
updateBalance(walletService.getBalanceForAddress(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disarm() {
|
public void cleanup() {
|
||||||
walletService.removeBalanceListener(balanceListener);
|
walletService.removeBalanceListener(balanceListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,11 +31,14 @@ import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.bitcoinj.core.TransactionConfidence;
|
import org.bitcoinj.core.TransactionConfidence;
|
||||||
|
|
||||||
public class BalanceWithConfirmationTextField extends AnchorPane {
|
public class BalanceWithConfirmationTextField extends AnchorPane {
|
||||||
|
|
||||||
private static WalletService walletService;
|
private static WalletService walletService;
|
||||||
|
private BalanceListener balanceListener;
|
||||||
|
private AddressConfidenceListener confidenceListener;
|
||||||
|
|
||||||
public static void setWalletService(WalletService walletService) {
|
public static void setWalletService(WalletService walletService) {
|
||||||
BalanceWithConfirmationTextField.walletService = walletService;
|
BalanceWithConfirmationTextField.walletService = walletService;
|
||||||
|
@ -77,22 +80,29 @@ public class BalanceWithConfirmationTextField extends AnchorPane {
|
||||||
getChildren().addAll(textField, progressIndicator);
|
getChildren().addAll(textField, progressIndicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void cleanup() {
|
||||||
|
walletService.removeBalanceListener(balanceListener);
|
||||||
|
walletService.removeAddressConfidenceListener(confidenceListener);
|
||||||
|
}
|
||||||
|
|
||||||
public void setup(Address address, BSFormatter formatter) {
|
public void setup(Address address, BSFormatter formatter) {
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
walletService.addAddressConfidenceListener(new AddressConfidenceListener(address) {
|
confidenceListener = new AddressConfidenceListener(address) {
|
||||||
@Override
|
@Override
|
||||||
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
|
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
|
||||||
updateConfidence(confidence);
|
updateConfidence(confidence);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
walletService.addAddressConfidenceListener(confidenceListener);
|
||||||
updateConfidence(walletService.getConfidenceForAddress(address));
|
updateConfidence(walletService.getConfidenceForAddress(address));
|
||||||
|
|
||||||
walletService.addBalanceListener(new BalanceListener(address) {
|
balanceListener = new BalanceListener(address) {
|
||||||
@Override
|
@Override
|
||||||
public void onBalanceChanged(Coin balance) {
|
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||||
updateBalance(balance);
|
updateBalance(balance);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
walletService.addBalanceListener(balanceListener);
|
||||||
updateBalance(walletService.getBalanceForAddress(address));
|
updateBalance(walletService.getBalanceForAddress(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -408,7 +408,7 @@ public class MainViewModel implements ViewModel {
|
||||||
|
|
||||||
walletService.addBalanceListener(new BalanceListener() {
|
walletService.addBalanceListener(new BalanceListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onBalanceChanged(Coin balance) {
|
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||||
updateBalance();
|
updateBalance();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -42,7 +42,6 @@ public class AccountView extends ActivatableView<TabPane, AccountViewModel> {
|
||||||
@FXML
|
@FXML
|
||||||
Tab accountSettingsTab;
|
Tab accountSettingsTab;
|
||||||
|
|
||||||
|
|
||||||
private Navigation.Listener navigationListener;
|
private Navigation.Listener navigationListener;
|
||||||
private ChangeListener<Tab> tabChangeListener;
|
private ChangeListener<Tab> tabChangeListener;
|
||||||
|
|
||||||
|
|
|
@ -19,18 +19,10 @@ package io.bitsquare.gui.main.account;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import io.bitsquare.gui.common.model.ViewModel;
|
import io.bitsquare.gui.common.model.ViewModel;
|
||||||
import io.bitsquare.user.User;
|
|
||||||
|
|
||||||
class AccountViewModel implements ViewModel {
|
class AccountViewModel implements ViewModel {
|
||||||
|
|
||||||
private final User user;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public AccountViewModel(User user) {
|
public AccountViewModel() {
|
||||||
this.user = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean getNeedRegistration() {
|
|
||||||
return user.getAccountId() == null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ public class ArbitratorRegistrationView extends ActivatableViewAndModel<VBox, Ar
|
||||||
|
|
||||||
private ChangeListener<Arbitrator> arbitratorChangeListener;
|
private ChangeListener<Arbitrator> arbitratorChangeListener;
|
||||||
private EnterPrivKeyPopup enterPrivKeyPopup;
|
private EnterPrivKeyPopup enterPrivKeyPopup;
|
||||||
|
private ListChangeListener<String> listChangeListener;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -84,6 +85,8 @@ public class ArbitratorRegistrationView extends ActivatableViewAndModel<VBox, Ar
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
|
model.myArbitratorProperty.removeListener(arbitratorChangeListener);
|
||||||
|
languagesListView.getItems().removeListener(listChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTabSelection(boolean isSelectedTab) {
|
public void onTabSelection(boolean isSelectedTab) {
|
||||||
|
@ -106,8 +109,8 @@ public class ArbitratorRegistrationView extends ActivatableViewAndModel<VBox, Ar
|
||||||
private void updateLanguageList() {
|
private void updateLanguageList() {
|
||||||
languagesListView.setItems(model.languageCodes);
|
languagesListView.setItems(model.languageCodes);
|
||||||
languagesListView.setPrefHeight(languagesListView.getItems().size() * Layout.LIST_ROW_HEIGHT + 2);
|
languagesListView.setPrefHeight(languagesListView.getItems().size() * Layout.LIST_ROW_HEIGHT + 2);
|
||||||
languagesListView.getItems().addListener((ListChangeListener<String>)
|
listChangeListener = c -> languagesListView.setPrefHeight(languagesListView.getItems().size() * Layout.LIST_ROW_HEIGHT + 2);
|
||||||
c -> languagesListView.setPrefHeight(languagesListView.getItems().size() * Layout.LIST_ROW_HEIGHT + 2));
|
languagesListView.getItems().addListener(listChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildUI() {
|
private void buildUI() {
|
||||||
|
|
|
@ -26,7 +26,9 @@ import io.bitsquare.gui.popups.Popup;
|
||||||
import io.bitsquare.gui.util.ImageUtil;
|
import io.bitsquare.gui.util.ImageUtil;
|
||||||
import io.bitsquare.gui.util.Layout;
|
import io.bitsquare.gui.util.Layout;
|
||||||
import io.bitsquare.locale.LanguageUtil;
|
import io.bitsquare.locale.LanguageUtil;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.geometry.HPos;
|
import javafx.geometry.HPos;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
|
@ -52,6 +54,9 @@ public class ArbitratorSelectionView extends ActivatableViewAndModel<GridPane, A
|
||||||
private TableView<ArbitratorListItem> table;
|
private TableView<ArbitratorListItem> table;
|
||||||
private int gridRow = 0;
|
private int gridRow = 0;
|
||||||
private CheckBox autoSelectAllMatchingCheckBox;
|
private CheckBox autoSelectAllMatchingCheckBox;
|
||||||
|
private ListChangeListener<String> listChangeListener;
|
||||||
|
private ListChangeListener<String> languageCodesListChangeListener;
|
||||||
|
private ChangeListener<Boolean> isSelectedChangeListener;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -68,13 +73,12 @@ public class ArbitratorSelectionView extends ActivatableViewAndModel<GridPane, A
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
addLanguageGroup();
|
addLanguageGroup();
|
||||||
addArbitratorsGroup();
|
addArbitratorsGroup();
|
||||||
|
listChangeListener = c -> languagesListView.setPrefHeight(languagesListView.getItems().size() * Layout.LIST_ROW_HEIGHT + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void activate() {
|
protected void activate() {
|
||||||
languagesListView.getItems().addListener((ListChangeListener<String>) c -> {
|
languagesListView.getItems().addListener(listChangeListener);
|
||||||
languagesListView.setPrefHeight(languagesListView.getItems().size() * Layout.LIST_ROW_HEIGHT + 2);
|
|
||||||
});
|
|
||||||
languageComboBox.setItems(model.allLanguageCodes);
|
languageComboBox.setItems(model.allLanguageCodes);
|
||||||
languagesListView.setItems(model.languageCodes);
|
languagesListView.setItems(model.languageCodes);
|
||||||
languagesListView.setPrefHeight(languagesListView.getItems().size() * Layout.LIST_ROW_HEIGHT + 2);
|
languagesListView.setPrefHeight(languagesListView.getItems().size() * Layout.LIST_ROW_HEIGHT + 2);
|
||||||
|
@ -85,6 +89,8 @@ public class ArbitratorSelectionView extends ActivatableViewAndModel<GridPane, A
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
|
languagesListView.getItems().removeListener(listChangeListener);
|
||||||
|
model.languageCodes.removeListener(languageCodesListChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -222,6 +228,7 @@ public class ArbitratorSelectionView extends ActivatableViewAndModel<GridPane, A
|
||||||
return new TableCell<ArbitratorListItem, ArbitratorListItem>() {
|
return new TableCell<ArbitratorListItem, ArbitratorListItem>() {
|
||||||
private final CheckBox checkBox = new CheckBox();
|
private final CheckBox checkBox = new CheckBox();
|
||||||
private TableRow tableRow;
|
private TableRow tableRow;
|
||||||
|
private BooleanProperty selectedProperty;
|
||||||
|
|
||||||
private void updateDisableState(final ArbitratorListItem item) {
|
private void updateDisableState(final ArbitratorListItem item) {
|
||||||
boolean selected = model.isAcceptedArbitrator(item.arbitrator);
|
boolean selected = model.isAcceptedArbitrator(item.arbitrator);
|
||||||
|
@ -261,8 +268,12 @@ public class ArbitratorSelectionView extends ActivatableViewAndModel<GridPane, A
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
if (item != null && !empty) {
|
if (item != null && !empty) {
|
||||||
model.languageCodes.addListener((ListChangeListener<String>) c -> updateDisableState(item));
|
selectedProperty = item.isSelectedProperty();
|
||||||
item.isSelectedProperty().addListener((observable, oldValue, newValue) -> checkBox.setSelected(newValue));
|
languageCodesListChangeListener = c -> updateDisableState(item);
|
||||||
|
model.languageCodes.addListener(languageCodesListChangeListener);
|
||||||
|
|
||||||
|
isSelectedChangeListener = (observable, oldValue, newValue) -> checkBox.setSelected(newValue);
|
||||||
|
selectedProperty.addListener(isSelectedChangeListener);
|
||||||
|
|
||||||
checkBox.setSelected(model.isAcceptedArbitrator(item.arbitrator));
|
checkBox.setSelected(model.isAcceptedArbitrator(item.arbitrator));
|
||||||
checkBox.setOnAction(e -> {
|
checkBox.setOnAction(e -> {
|
||||||
|
@ -281,6 +292,10 @@ public class ArbitratorSelectionView extends ActivatableViewAndModel<GridPane, A
|
||||||
updateDisableState(item);
|
updateDisableState(item);
|
||||||
setGraphic(checkBox);
|
setGraphic(checkBox);
|
||||||
} else {
|
} else {
|
||||||
|
model.languageCodes.removeListener(languageCodesListChangeListener);
|
||||||
|
if (selectedProperty != null)
|
||||||
|
selectedProperty.removeListener(isSelectedChangeListener);
|
||||||
|
|
||||||
setGraphic(null);
|
setGraphic(null);
|
||||||
|
|
||||||
if (checkBox != null)
|
if (checkBox != null)
|
||||||
|
|
|
@ -45,7 +45,6 @@ class ChangePasswordViewModel implements ViewModel {
|
||||||
repeatedPasswordField.addListener((ov) -> saveButtonDisabled.set(!validate()));
|
repeatedPasswordField.addListener((ov) -> saveButtonDisabled.set(!validate()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
boolean requestSavePassword() {
|
boolean requestSavePassword() {
|
||||||
if (validate()) {
|
if (validate()) {
|
||||||
savePassword(passwordField.get());
|
savePassword(passwordField.get());
|
||||||
|
|
|
@ -30,6 +30,7 @@ import io.bitsquare.gui.popups.Popup;
|
||||||
import io.bitsquare.gui.util.Layout;
|
import io.bitsquare.gui.util.Layout;
|
||||||
import io.bitsquare.gui.util.validation.InputValidator;
|
import io.bitsquare.gui.util.validation.InputValidator;
|
||||||
import io.bitsquare.gui.util.validation.PasswordValidator;
|
import io.bitsquare.gui.util.validation.PasswordValidator;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ProgressIndicator;
|
import javafx.scene.control.ProgressIndicator;
|
||||||
|
@ -54,6 +55,8 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
|
||||||
private TitledGroupBg headline;
|
private TitledGroupBg headline;
|
||||||
private int gridRow = 0;
|
private int gridRow = 0;
|
||||||
private Label repeatedPasswordLabel;
|
private Label repeatedPasswordLabel;
|
||||||
|
private ChangeListener<String> passwordFieldChangeListener;
|
||||||
|
private ChangeListener<String> repeatedPasswordFieldChangeListener;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -72,17 +75,13 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
|
||||||
headline = addTitledGroupBg(root, gridRow, 3, "");
|
headline = addTitledGroupBg(root, gridRow, 3, "");
|
||||||
passwordField = addLabelPasswordTextField(root, gridRow, "Enter password:", Layout.FIRST_ROW_DISTANCE).second;
|
passwordField = addLabelPasswordTextField(root, gridRow, "Enter password:", Layout.FIRST_ROW_DISTANCE).second;
|
||||||
passwordField.setValidator(passwordValidator);
|
passwordField.setValidator(passwordValidator);
|
||||||
passwordField.textProperty().addListener((observable, oldValue, newValue) -> {
|
passwordFieldChangeListener = (observable, oldValue, newValue) -> validatePasswords();
|
||||||
validatePasswords();
|
|
||||||
});
|
|
||||||
|
|
||||||
Tuple2<Label, PasswordTextField> tuple2 = addLabelPasswordTextField(root, ++gridRow, "Repeat password:");
|
Tuple2<Label, PasswordTextField> tuple2 = addLabelPasswordTextField(root, ++gridRow, "Repeat password:");
|
||||||
repeatedPasswordLabel = tuple2.first;
|
repeatedPasswordLabel = tuple2.first;
|
||||||
repeatedPasswordField = tuple2.second;
|
repeatedPasswordField = tuple2.second;
|
||||||
repeatedPasswordField.setValidator(passwordValidator);
|
repeatedPasswordField.setValidator(passwordValidator);
|
||||||
repeatedPasswordField.textProperty().addListener((observable, oldValue, newValue) -> {
|
repeatedPasswordFieldChangeListener = (observable, oldValue, newValue) -> validatePasswords();
|
||||||
validatePasswords();
|
|
||||||
});
|
|
||||||
|
|
||||||
Tuple3<Button, ProgressIndicator, Label> tuple = addButtonWithStatus(root, ++gridRow, "", 0);
|
Tuple3<Button, ProgressIndicator, Label> tuple = addButtonWithStatus(root, ++gridRow, "", 0);
|
||||||
pwButton = tuple.first;
|
pwButton = tuple.first;
|
||||||
|
@ -105,7 +104,6 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
|
||||||
else
|
else
|
||||||
keyCrypterScrypt = ScryptUtil.getKeyCrypterScrypt();
|
keyCrypterScrypt = ScryptUtil.getKeyCrypterScrypt();
|
||||||
|
|
||||||
|
|
||||||
ScryptUtil.deriveKeyWithScrypt(keyCrypterScrypt, passwordField.getText(), aesKey -> {
|
ScryptUtil.deriveKeyWithScrypt(keyCrypterScrypt, passwordField.getText(), aesKey -> {
|
||||||
deriveStatusLabel.setText("");
|
deriveStatusLabel.setText("");
|
||||||
progressIndicator.setVisible(false);
|
progressIndicator.setVisible(false);
|
||||||
|
@ -169,10 +167,16 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void activate() {
|
protected void activate() {
|
||||||
|
passwordField.textProperty().addListener(passwordFieldChangeListener);
|
||||||
|
repeatedPasswordField.textProperty().addListener(repeatedPasswordFieldChangeListener);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
|
passwordField.textProperty().removeListener(passwordFieldChangeListener);
|
||||||
|
repeatedPasswordField.textProperty().removeListener(repeatedPasswordFieldChangeListener);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validatePasswords() {
|
private void validatePasswords() {
|
||||||
|
|
|
@ -64,6 +64,7 @@ public class PaymentAccountView extends ActivatableViewAndModel<GridPane, Paymen
|
||||||
private Button addAccountButton;
|
private Button addAccountButton;
|
||||||
private Button saveNewAccountButton;
|
private Button saveNewAccountButton;
|
||||||
private int gridRow = 0;
|
private int gridRow = 0;
|
||||||
|
private ListChangeListener<PaymentAccount> paymentAccountListChangeListener;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public PaymentAccountView(PaymentAccountViewModel model,
|
public PaymentAccountView(PaymentAccountViewModel model,
|
||||||
|
@ -90,6 +91,7 @@ public class PaymentAccountView extends ActivatableViewAndModel<GridPane, Paymen
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
buildForm();
|
buildForm();
|
||||||
|
paymentAccountListChangeListener = c -> paymentAccountsComboBox.setDisable(model.getPaymentAccounts().size() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -102,13 +104,13 @@ public class PaymentAccountView extends ActivatableViewAndModel<GridPane, Paymen
|
||||||
paymentAccountsComboBox.setOnAction(paymentAccountsComboBoxHandler);
|
paymentAccountsComboBox.setOnAction(paymentAccountsComboBoxHandler);
|
||||||
paymentAccountsComboBox.setVisibleRowCount(20);
|
paymentAccountsComboBox.setVisibleRowCount(20);
|
||||||
|
|
||||||
model.getPaymentAccounts().addListener(
|
model.getPaymentAccounts().addListener(paymentAccountListChangeListener);
|
||||||
(ListChangeListener<PaymentAccount>) c -> paymentAccountsComboBox.setDisable(model.getPaymentAccounts().size() == 0));
|
|
||||||
paymentAccountsComboBox.setDisable(model.getPaymentAccounts().size() == 0);
|
paymentAccountsComboBox.setDisable(model.getPaymentAccounts().size() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
|
model.getPaymentAccounts().removeListener(paymentAccountListChangeListener);
|
||||||
paymentAccountsComboBox.setOnAction(null);
|
paymentAccountsComboBox.setOnAction(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ import io.bitsquare.gui.popups.WalletPasswordPopup;
|
||||||
import io.bitsquare.gui.util.Layout;
|
import io.bitsquare.gui.util.Layout;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.DatePicker;
|
import javafx.scene.control.DatePicker;
|
||||||
import javafx.scene.control.TextArea;
|
import javafx.scene.control.TextArea;
|
||||||
|
@ -61,6 +62,12 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
|
||||||
|
|
||||||
private int gridRow = 0;
|
private int gridRow = 0;
|
||||||
private DeterministicSeed keyChainSeed;
|
private DeterministicSeed keyChainSeed;
|
||||||
|
private ChangeListener<Boolean> seedWordsValidChangeListener;
|
||||||
|
private SimpleBooleanProperty seedWordsValid;
|
||||||
|
private SimpleBooleanProperty dateValid;
|
||||||
|
private ChangeListener<String> seedWordsTextAreaChangeListener;
|
||||||
|
private ChangeListener<Boolean> datePickerChangeListener;
|
||||||
|
private ChangeListener<LocalDate> dateChangeListener;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -105,6 +112,11 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
|
seedWordsValid.removeListener(seedWordsValidChangeListener);
|
||||||
|
seedWordsTextArea.textProperty().removeListener(seedWordsTextAreaChangeListener);
|
||||||
|
dateValid.removeListener(datePickerChangeListener);
|
||||||
|
datePicker.valueProperty().removeListener(dateChangeListener);
|
||||||
|
|
||||||
seedWordsTextArea.setText("");
|
seedWordsTextArea.setText("");
|
||||||
datePicker.setValue(null);
|
datePicker.setValue(null);
|
||||||
restoreButton.disableProperty().unbind();
|
restoreButton.disableProperty().unbind();
|
||||||
|
@ -134,15 +146,18 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
|
||||||
restoreButton.setOnAction(e -> onRestore());
|
restoreButton.setOnAction(e -> onRestore());
|
||||||
|
|
||||||
BooleanProperty seedWordsEdited = new SimpleBooleanProperty();
|
BooleanProperty seedWordsEdited = new SimpleBooleanProperty();
|
||||||
BooleanProperty seedWordsValid = new SimpleBooleanProperty(true);
|
|
||||||
seedWordsValid.addListener((observable, oldValue, newValue) -> {
|
seedWordsValid = new SimpleBooleanProperty(true);
|
||||||
|
seedWordsValidChangeListener = (observable, oldValue, newValue) -> {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
seedWordsTextArea.getStyleClass().remove("validation_error");
|
seedWordsTextArea.getStyleClass().remove("validation_error");
|
||||||
} else {
|
} else {
|
||||||
seedWordsTextArea.getStyleClass().add("validation_error");
|
seedWordsTextArea.getStyleClass().add("validation_error");
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
seedWordsTextArea.textProperty().addListener((observable, oldValue, newValue) -> {
|
seedWordsValid.addListener(seedWordsValidChangeListener);
|
||||||
|
|
||||||
|
seedWordsTextAreaChangeListener = (observable, oldValue, newValue) -> {
|
||||||
seedWordsEdited.set(true);
|
seedWordsEdited.set(true);
|
||||||
try {
|
try {
|
||||||
MnemonicCode codec = new MnemonicCode();
|
MnemonicCode codec = new MnemonicCode();
|
||||||
|
@ -154,18 +169,22 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
|
||||||
|
|
||||||
if (creationDate.equals(datePicker.getValue()))
|
if (creationDate.equals(datePicker.getValue()))
|
||||||
datePicker.setValue(null);
|
datePicker.setValue(null);
|
||||||
});
|
};
|
||||||
|
seedWordsTextArea.textProperty().addListener(seedWordsTextAreaChangeListener);
|
||||||
|
|
||||||
BooleanProperty dateValid = new SimpleBooleanProperty(true);
|
dateValid = new SimpleBooleanProperty(true);
|
||||||
dateValid.addListener((observable, oldValue, newValue) -> {
|
datePickerChangeListener = (observable, oldValue, newValue) -> {
|
||||||
if (newValue)
|
if (newValue)
|
||||||
datePicker.getStyleClass().remove("validation_error");
|
datePicker.getStyleClass().remove("validation_error");
|
||||||
else
|
else
|
||||||
datePicker.getStyleClass().add("validation_error");
|
datePicker.getStyleClass().add("validation_error");
|
||||||
});
|
};
|
||||||
datePicker.valueProperty().addListener((observable, oldValue, newValue) -> {
|
dateValid.addListener(datePickerChangeListener);
|
||||||
|
|
||||||
|
dateChangeListener = (observable, oldValue, newValue) -> {
|
||||||
dateValid.set(newValue != null && !newValue.isAfter(LocalDate.now()));
|
dateValid.set(newValue != null && !newValue.isAfter(LocalDate.now()));
|
||||||
});
|
};
|
||||||
|
datePicker.valueProperty().addListener(dateChangeListener);
|
||||||
|
|
||||||
restoreButton.disableProperty().bind(createBooleanBinding(() -> !seedWordsValid.get() || !dateValid.get() || !seedWordsEdited.get(),
|
restoreButton.disableProperty().bind(createBooleanBinding(() -> !seedWordsValid.get() || !dateValid.get() || !seedWordsEdited.get(),
|
||||||
seedWordsValid, dateValid, seedWordsEdited));
|
seedWordsValid, dateValid, seedWordsEdited));
|
||||||
|
|
|
@ -29,6 +29,7 @@ import io.bitsquare.gui.main.account.content.password.PasswordView;
|
||||||
import io.bitsquare.gui.main.account.content.paymentsaccount.PaymentAccountView;
|
import io.bitsquare.gui.main.account.content.paymentsaccount.PaymentAccountView;
|
||||||
import io.bitsquare.gui.main.account.content.seedwords.SeedWordsView;
|
import io.bitsquare.gui.main.account.content.seedwords.SeedWordsView;
|
||||||
import io.bitsquare.gui.util.Colors;
|
import io.bitsquare.gui.util.Colors;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
|
@ -95,11 +96,22 @@ public class AccountSettingsView extends ActivatableViewAndModel {
|
||||||
selecteedViewClass = viewPath.get(3);
|
selecteedViewClass = viewPath.get(3);
|
||||||
loadView(selecteedViewClass);
|
loadView(selecteedViewClass);
|
||||||
}
|
}
|
||||||
|
paymentAccount.activate();
|
||||||
|
arbitratorSelection.activate();
|
||||||
|
password.activate();
|
||||||
|
seedWords.activate();
|
||||||
|
backup.activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
navigation.removeListener(listener);
|
navigation.removeListener(listener);
|
||||||
|
|
||||||
|
paymentAccount.deactivate();
|
||||||
|
arbitratorSelection.deactivate();
|
||||||
|
password.deactivate();
|
||||||
|
seedWords.deactivate();
|
||||||
|
backup.deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadView(Class<? extends View> viewClass) {
|
private void loadView(Class<? extends View> viewClass) {
|
||||||
|
@ -133,7 +145,14 @@ public class AccountSettingsView extends ActivatableViewAndModel {
|
||||||
|
|
||||||
class MenuItem extends ToggleButton {
|
class MenuItem extends ToggleButton {
|
||||||
|
|
||||||
|
private final ChangeListener<Boolean> selectedPropertyChangeListener;
|
||||||
|
private final ChangeListener<Boolean> disablePropertyChangeListener;
|
||||||
|
private Navigation navigation;
|
||||||
|
private Class<? extends View> viewClass;
|
||||||
|
|
||||||
MenuItem(Navigation navigation, ToggleGroup toggleGroup, String title, Class<? extends View> viewClass, AwesomeIcon awesomeIcon) {
|
MenuItem(Navigation navigation, ToggleGroup toggleGroup, String title, Class<? extends View> viewClass, AwesomeIcon awesomeIcon) {
|
||||||
|
this.navigation = navigation;
|
||||||
|
this.viewClass = viewClass;
|
||||||
|
|
||||||
setToggleGroup(toggleGroup);
|
setToggleGroup(toggleGroup);
|
||||||
setText(title);
|
setText(title);
|
||||||
|
@ -151,10 +170,7 @@ class MenuItem extends ToggleButton {
|
||||||
icon.setMaxWidth(25);
|
icon.setMaxWidth(25);
|
||||||
setGraphic(icon);
|
setGraphic(icon);
|
||||||
|
|
||||||
setOnAction((event) ->
|
selectedPropertyChangeListener = (ov, oldValue, newValue) -> {
|
||||||
navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class, viewClass));
|
|
||||||
|
|
||||||
selectedProperty().addListener((ov, oldValue, newValue) -> {
|
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
setId("account-settings-item-background-selected");
|
setId("account-settings-item-background-selected");
|
||||||
icon.setTextFill(Colors.BLUE);
|
icon.setTextFill(Colors.BLUE);
|
||||||
|
@ -162,9 +178,9 @@ class MenuItem extends ToggleButton {
|
||||||
setId("account-settings-item-background-active");
|
setId("account-settings-item-background-active");
|
||||||
icon.setTextFill(Paint.valueOf("#333"));
|
icon.setTextFill(Paint.valueOf("#333"));
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
disableProperty().addListener((ov, oldValue, newValue) -> {
|
disablePropertyChangeListener = (ov, oldValue, newValue) -> {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
setId("account-settings-item-background-disabled");
|
setId("account-settings-item-background-disabled");
|
||||||
icon.setTextFill(Paint.valueOf("#ccc"));
|
icon.setTextFill(Paint.valueOf("#ccc"));
|
||||||
|
@ -172,7 +188,19 @@ class MenuItem extends ToggleButton {
|
||||||
setId("account-settings-item-background-active");
|
setId("account-settings-item-background-active");
|
||||||
icon.setTextFill(Paint.valueOf("#333"));
|
icon.setTextFill(Paint.valueOf("#333"));
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void activate() {
|
||||||
|
setOnAction((event) -> navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class, viewClass));
|
||||||
|
selectedProperty().addListener(selectedPropertyChangeListener);
|
||||||
|
disableProperty().addListener(disablePropertyChangeListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deactivate() {
|
||||||
|
setOnAction(null);
|
||||||
|
selectedProperty().removeListener(selectedPropertyChangeListener);
|
||||||
|
disableProperty().removeListener(disablePropertyChangeListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
AnchorPane.topAnchor="0.0"
|
AnchorPane.topAnchor="0.0"
|
||||||
xmlns:fx="http://javafx.com/fxml">
|
xmlns:fx="http://javafx.com/fxml">
|
||||||
|
|
||||||
<Tab fx:id="tradersDisputesTab" text="Traders support tickets" closable="false"></Tab>
|
<Tab fx:id="tradersDisputesTab" text="Support tickets" closable="false"></Tab>
|
||||||
<Tab fx:id="arbitratorsDisputesTab" text="Arbitrators support tickets" closable="false"/>
|
|
||||||
|
|
||||||
</TabPane>
|
</TabPane>
|
||||||
|
|
|
@ -40,7 +40,9 @@ import javax.inject.Inject;
|
||||||
public class DisputesView extends ActivatableViewAndModel<TabPane, Activatable> {
|
public class DisputesView extends ActivatableViewAndModel<TabPane, Activatable> {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
Tab tradersDisputesTab, arbitratorsDisputesTab;
|
Tab tradersDisputesTab;
|
||||||
|
|
||||||
|
private Tab arbitratorsDisputesTab;
|
||||||
|
|
||||||
private final Navigation navigation;
|
private final Navigation navigation;
|
||||||
private final ArbitratorManager arbitratorManager;
|
private final ArbitratorManager arbitratorManager;
|
||||||
|
@ -51,6 +53,7 @@ public class DisputesView extends ActivatableViewAndModel<TabPane, Activatable>
|
||||||
private Tab currentTab;
|
private Tab currentTab;
|
||||||
private final ViewLoader viewLoader;
|
private final ViewLoader viewLoader;
|
||||||
private MapChangeListener<NodeAddress, Arbitrator> arbitratorMapChangeListener;
|
private MapChangeListener<NodeAddress, Arbitrator> arbitratorMapChangeListener;
|
||||||
|
private boolean isArbitrator;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public DisputesView(CachingViewLoader viewLoader, Navigation navigation, ArbitratorManager arbitratorManager, KeyRing keyRing) {
|
public DisputesView(CachingViewLoader viewLoader, Navigation navigation, ArbitratorManager arbitratorManager, KeyRing keyRing) {
|
||||||
|
@ -58,6 +61,8 @@ public class DisputesView extends ActivatableViewAndModel<TabPane, Activatable>
|
||||||
this.navigation = navigation;
|
this.navigation = navigation;
|
||||||
this.arbitratorManager = arbitratorManager;
|
this.arbitratorManager = arbitratorManager;
|
||||||
this.keyRing = keyRing;
|
this.keyRing = keyRing;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -79,12 +84,16 @@ public class DisputesView extends ActivatableViewAndModel<TabPane, Activatable>
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateArbitratorsDisputesTabDisableState() {
|
private void updateArbitratorsDisputesTabDisableState() {
|
||||||
boolean isArbitrator = arbitratorManager.getArbitratorsObservableMap().values().stream()
|
isArbitrator = arbitratorManager.getArbitratorsObservableMap().values().stream()
|
||||||
.filter(e -> e.getPubKeyRing() != null && e.getPubKeyRing().equals(keyRing.getPubKeyRing()))
|
.filter(e -> e.getPubKeyRing() != null && e.getPubKeyRing().equals(keyRing.getPubKeyRing()))
|
||||||
.findAny().isPresent();
|
.findAny().isPresent();
|
||||||
arbitratorsDisputesTab.setDisable(!isArbitrator);
|
|
||||||
if (arbitratorsDisputesTab.getContent() != null)
|
if (arbitratorsDisputesTab == null && isArbitrator) {
|
||||||
arbitratorsDisputesTab.getContent().setDisable(!isArbitrator);
|
arbitratorsDisputesTab = new Tab("Arbitrators support tickets");
|
||||||
|
arbitratorsDisputesTab.setClosable(false);
|
||||||
|
root.getTabs().add(arbitratorsDisputesTab);
|
||||||
|
tradersDisputesTab.setText("Traders support tickets");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -96,10 +105,10 @@ public class DisputesView extends ActivatableViewAndModel<TabPane, Activatable>
|
||||||
root.getSelectionModel().selectedItemProperty().addListener(tabChangeListener);
|
root.getSelectionModel().selectedItemProperty().addListener(tabChangeListener);
|
||||||
navigation.addListener(navigationListener);
|
navigation.addListener(navigationListener);
|
||||||
|
|
||||||
if (root.getSelectionModel().getSelectedItem() == tradersDisputesTab)
|
if (arbitratorsDisputesTab != null && root.getSelectionModel().getSelectedItem() == arbitratorsDisputesTab)
|
||||||
navigation.navigateTo(MainView.class, DisputesView.class, TraderDisputeView.class);
|
|
||||||
else if (root.getSelectionModel().getSelectedItem() == arbitratorsDisputesTab)
|
|
||||||
navigation.navigateTo(MainView.class, DisputesView.class, ArbitratorDisputeView.class);
|
navigation.navigateTo(MainView.class, DisputesView.class, ArbitratorDisputeView.class);
|
||||||
|
else
|
||||||
|
navigation.navigateTo(MainView.class, DisputesView.class, TraderDisputeView.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -117,9 +126,9 @@ public class DisputesView extends ActivatableViewAndModel<TabPane, Activatable>
|
||||||
|
|
||||||
View view = viewLoader.load(viewClass);
|
View view = viewLoader.load(viewClass);
|
||||||
|
|
||||||
if (view instanceof ArbitratorDisputeView)
|
if (arbitratorsDisputesTab != null && view instanceof ArbitratorDisputeView)
|
||||||
currentTab = arbitratorsDisputesTab;
|
currentTab = arbitratorsDisputesTab;
|
||||||
else if (view instanceof TraderDisputeView)
|
else
|
||||||
currentTab = tradersDisputesTab;
|
currentTab = tradersDisputesTab;
|
||||||
|
|
||||||
currentTab.setContent(view.getRoot());
|
currentTab.setContent(view.getRoot());
|
||||||
|
|
|
@ -38,6 +38,7 @@ import io.bitsquare.gui.util.GUIUtil;
|
||||||
import io.bitsquare.p2p.network.Connection;
|
import io.bitsquare.p2p.network.Connection;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.TradeManager;
|
||||||
|
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
|
@ -56,6 +57,7 @@ import javafx.util.Callback;
|
||||||
import org.reactfx.util.FxTimer;
|
import org.reactfx.util.FxTimer;
|
||||||
import org.reactfx.util.Timer;
|
import org.reactfx.util.Timer;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -92,6 +94,13 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
private VBox messagesInputBox;
|
private VBox messagesInputBox;
|
||||||
private ProgressIndicator sendMsgProgressIndicator;
|
private ProgressIndicator sendMsgProgressIndicator;
|
||||||
private Label sendMsgInfoLabel;
|
private Label sendMsgInfoLabel;
|
||||||
|
private ChangeListener<Boolean> arrivedPropertyListener;
|
||||||
|
private ChangeListener<Boolean> storedInMailboxPropertyListener;
|
||||||
|
@Nullable
|
||||||
|
private DisputeDirectMessage disputeDirectMessage;
|
||||||
|
private ListChangeListener<DisputeDirectMessage> disputeDirectMessageListListener;
|
||||||
|
private ChangeListener<String> inputTextAreaListener;
|
||||||
|
private ChangeListener<Boolean> selectedDisputeClosedPropertyListener;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -159,6 +168,23 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
disputesTable.getSelectionModel().selectedItemProperty().removeListener(disputeChangeListener);
|
disputesTable.getSelectionModel().selectedItemProperty().removeListener(disputeChangeListener);
|
||||||
|
|
||||||
|
if (disputeDirectMessage != null) {
|
||||||
|
disputeDirectMessage.arrivedProperty().removeListener(arrivedPropertyListener);
|
||||||
|
disputeDirectMessage.storedInMailboxProperty().removeListener(storedInMailboxPropertyListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedDispute != null) {
|
||||||
|
selectedDispute.isClosedProperty().removeListener(selectedDisputeClosedPropertyListener);
|
||||||
|
ObservableList<DisputeDirectMessage> disputeDirectMessages = selectedDispute.getDisputeDirectMessagesAsObservableList();
|
||||||
|
if (disputeDirectMessages != null) {
|
||||||
|
disputeDirectMessages.removeListener(disputeDirectMessageListListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputTextArea != null)
|
||||||
|
inputTextArea.textProperty().removeListener(inputTextAreaListener);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setFilteredListPredicate(FilteredList<Dispute> filteredList) {
|
protected void setFilteredListPredicate(FilteredList<Dispute> filteredList) {
|
||||||
|
@ -175,7 +201,12 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSendMessage(String inputText, Dispute dispute) {
|
private void onSendMessage(String inputText, Dispute dispute) {
|
||||||
DisputeDirectMessage disputeDirectMessage = disputeManager.sendDisputeDirectMessage(dispute, inputText, new ArrayList<>(tempAttachments));
|
if (disputeDirectMessage != null) {
|
||||||
|
disputeDirectMessage.arrivedProperty().removeListener(arrivedPropertyListener);
|
||||||
|
disputeDirectMessage.storedInMailboxProperty().removeListener(storedInMailboxPropertyListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
disputeDirectMessage = disputeManager.sendDisputeDirectMessage(dispute, inputText, new ArrayList<>(tempAttachments));
|
||||||
tempAttachments.clear();
|
tempAttachments.clear();
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
|
|
||||||
|
@ -192,19 +223,21 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
sendMsgProgressIndicator.setManaged(true);
|
sendMsgProgressIndicator.setManaged(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
disputeDirectMessage.arrivedProperty().addListener((observable, oldValue, newValue) -> {
|
arrivedPropertyListener = (observable, oldValue, newValue) -> {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
hideSendMsgInfo(timer);
|
hideSendMsgInfo(timer);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
disputeDirectMessage.storedInMailboxProperty().addListener((observable, oldValue, newValue) -> {
|
disputeDirectMessage.arrivedProperty().addListener(arrivedPropertyListener);
|
||||||
|
storedInMailboxPropertyListener = (observable, oldValue, newValue) -> {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
sendMsgInfoLabel.setVisible(true);
|
sendMsgInfoLabel.setVisible(true);
|
||||||
sendMsgInfoLabel.setManaged(true);
|
sendMsgInfoLabel.setManaged(true);
|
||||||
sendMsgInfoLabel.setText("Receiver is not online. Message is saved to his mailbox.");
|
sendMsgInfoLabel.setText("Receiver is not online. Message is saved to his mailbox.");
|
||||||
hideSendMsgInfo(timer);
|
hideSendMsgInfo(timer);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
disputeDirectMessage.storedInMailboxProperty().addListener(storedInMailboxPropertyListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hideSendMsgInfo(Timer timer) {
|
private void hideSendMsgInfo(Timer timer) {
|
||||||
|
@ -221,7 +254,8 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCloseDispute(Dispute dispute) {
|
private void onCloseDispute(Dispute dispute) {
|
||||||
disputeSummaryPopup.onFinalizeDispute(() -> messagesAnchorPane.getChildren().remove(messagesInputBox)).show(dispute);
|
disputeSummaryPopup.onFinalizeDispute(() -> messagesAnchorPane.getChildren().remove(messagesInputBox))
|
||||||
|
.show(dispute);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onRequestUpload() {
|
private void onRequestUpload() {
|
||||||
|
@ -275,6 +309,14 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSelectDispute(Dispute dispute) {
|
private void onSelectDispute(Dispute dispute) {
|
||||||
|
if (selectedDispute != null) {
|
||||||
|
selectedDispute.isClosedProperty().removeListener(selectedDisputeClosedPropertyListener);
|
||||||
|
ObservableList<DisputeDirectMessage> disputeDirectMessages = selectedDispute.getDisputeDirectMessagesAsObservableList();
|
||||||
|
if (disputeDirectMessages != null) {
|
||||||
|
disputeDirectMessages.removeListener(disputeDirectMessageListListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (dispute == null) {
|
if (dispute == null) {
|
||||||
if (root.getChildren().size() > 1)
|
if (root.getChildren().size() > 1)
|
||||||
root.getChildren().remove(1);
|
root.getChildren().remove(1);
|
||||||
|
@ -283,7 +325,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
} else if (selectedDispute != dispute) {
|
} else if (selectedDispute != dispute) {
|
||||||
this.selectedDispute = dispute;
|
this.selectedDispute = dispute;
|
||||||
|
|
||||||
boolean isTrader = disputeManager.isTrader(dispute);
|
boolean isTrader = disputeManager.isTrader(selectedDispute);
|
||||||
|
|
||||||
TableGroupHeadline tableGroupHeadline = new TableGroupHeadline();
|
TableGroupHeadline tableGroupHeadline = new TableGroupHeadline();
|
||||||
tableGroupHeadline.setText("Messages");
|
tableGroupHeadline.setText("Messages");
|
||||||
|
@ -293,10 +335,11 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
AnchorPane.setBottomAnchor(tableGroupHeadline, 0d);
|
AnchorPane.setBottomAnchor(tableGroupHeadline, 0d);
|
||||||
AnchorPane.setLeftAnchor(tableGroupHeadline, 0d);
|
AnchorPane.setLeftAnchor(tableGroupHeadline, 0d);
|
||||||
|
|
||||||
ObservableList<DisputeDirectMessage> list = dispute.getDisputeDirectMessagesAsObservableList();
|
ObservableList<DisputeDirectMessage> disputeDirectMessages = selectedDispute.getDisputeDirectMessagesAsObservableList();
|
||||||
SortedList<DisputeDirectMessage> sortedList = new SortedList<>(list);
|
SortedList<DisputeDirectMessage> sortedList = new SortedList<>(disputeDirectMessages);
|
||||||
sortedList.setComparator((o1, o2) -> o1.getDate().compareTo(o2.getDate()));
|
sortedList.setComparator((o1, o2) -> o1.getDate().compareTo(o2.getDate()));
|
||||||
list.addListener((ListChangeListener<DisputeDirectMessage>) c -> scrollToBottom());
|
disputeDirectMessageListListener = c -> scrollToBottom();
|
||||||
|
disputeDirectMessages.addListener(disputeDirectMessageListListener);
|
||||||
messageListView = new ListView<>(sortedList);
|
messageListView = new ListView<>(sortedList);
|
||||||
messageListView.setId("message-list-view");
|
messageListView.setId("message-list-view");
|
||||||
messageListView.prefWidthProperty().bind(root.widthProperty());
|
messageListView.prefWidthProperty().bind(root.widthProperty());
|
||||||
|
@ -315,11 +358,13 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
|
|
||||||
Button sendButton = new Button("Send");
|
Button sendButton = new Button("Send");
|
||||||
sendButton.setDefaultButton(true);
|
sendButton.setDefaultButton(true);
|
||||||
sendButton.setOnAction(e -> onSendMessage(inputTextArea.getText(), dispute));
|
sendButton.setOnAction(e -> onSendMessage(inputTextArea.getText(), selectedDispute));
|
||||||
sendButton.setDisable(true);
|
sendButton.setDisable(true);
|
||||||
inputTextArea.textProperty().addListener((observable, oldValue, newValue) -> {
|
inputTextAreaListener = (observable, oldValue, newValue) ->
|
||||||
sendButton.setDisable(newValue.length() == 0 && tempAttachments.size() == 0 && dispute.disputeResultProperty().get() == null);
|
sendButton.setDisable(newValue.length() == 0
|
||||||
});
|
&& tempAttachments.size() == 0 &&
|
||||||
|
selectedDispute.disputeResultProperty().get() == null);
|
||||||
|
inputTextArea.textProperty().addListener(inputTextAreaListener);
|
||||||
|
|
||||||
Button uploadButton = new Button("Add attachments");
|
Button uploadButton = new Button("Add attachments");
|
||||||
uploadButton.setOnAction(e -> onRequestUpload());
|
uploadButton.setOnAction(e -> onRequestUpload());
|
||||||
|
@ -335,19 +380,20 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
sendMsgProgressIndicator.setVisible(false);
|
sendMsgProgressIndicator.setVisible(false);
|
||||||
sendMsgProgressIndicator.setManaged(false);
|
sendMsgProgressIndicator.setManaged(false);
|
||||||
|
|
||||||
dispute.isClosedProperty().addListener((observable, oldValue, newValue) -> {
|
selectedDisputeClosedPropertyListener = (observable, oldValue, newValue) -> {
|
||||||
messagesInputBox.setVisible(!newValue);
|
messagesInputBox.setVisible(!newValue);
|
||||||
messagesInputBox.setManaged(!newValue);
|
messagesInputBox.setManaged(!newValue);
|
||||||
AnchorPane.setBottomAnchor(messageListView, newValue ? 0d : 120d);
|
AnchorPane.setBottomAnchor(messageListView, newValue ? 0d : 120d);
|
||||||
});
|
};
|
||||||
if (!dispute.isClosed()) {
|
selectedDispute.isClosedProperty().addListener(selectedDisputeClosedPropertyListener);
|
||||||
|
if (!selectedDispute.isClosed()) {
|
||||||
HBox buttonBox = new HBox();
|
HBox buttonBox = new HBox();
|
||||||
buttonBox.setSpacing(10);
|
buttonBox.setSpacing(10);
|
||||||
buttonBox.getChildren().addAll(sendButton, uploadButton, sendMsgProgressIndicator, sendMsgInfoLabel);
|
buttonBox.getChildren().addAll(sendButton, uploadButton, sendMsgProgressIndicator, sendMsgInfoLabel);
|
||||||
|
|
||||||
if (!isTrader) {
|
if (!isTrader) {
|
||||||
Button closeDisputeButton = new Button("Close ticket");
|
Button closeDisputeButton = new Button("Close ticket");
|
||||||
closeDisputeButton.setOnAction(e -> onCloseDispute(dispute));
|
closeDisputeButton.setOnAction(e -> onCloseDispute(selectedDispute));
|
||||||
closeDisputeButton.setDefaultButton(true);
|
closeDisputeButton.setDefaultButton(true);
|
||||||
Pane spacer = new Pane();
|
Pane spacer = new Pane();
|
||||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
HBox.setHgrow(spacer, Priority.ALWAYS);
|
||||||
|
@ -375,6 +421,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
@Override
|
@Override
|
||||||
public ListCell<DisputeDirectMessage> call(ListView<DisputeDirectMessage> list) {
|
public ListCell<DisputeDirectMessage> call(ListView<DisputeDirectMessage> list) {
|
||||||
return new ListCell<DisputeDirectMessage>() {
|
return new ListCell<DisputeDirectMessage>() {
|
||||||
|
public ChangeListener<Number> sendMsgProgressIndicatorListener;
|
||||||
final Pane bg = new Pane();
|
final Pane bg = new Pane();
|
||||||
final ImageView arrow = new ImageView();
|
final ImageView arrow = new ImageView();
|
||||||
final Label headerLabel = new Label();
|
final Label headerLabel = new Label();
|
||||||
|
@ -434,14 +481,15 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
else
|
else
|
||||||
arrow.setId("bubble_arrow_blue_right");
|
arrow.setId("bubble_arrow_blue_right");
|
||||||
|
|
||||||
sendMsgProgressIndicator.progressProperty().addListener((observable, oldValue, newValue) -> {
|
sendMsgProgressIndicatorListener = (observable, oldValue, newValue) -> {
|
||||||
if ((double) oldValue == -1 && (double) newValue == 0) {
|
if ((double) oldValue == -1 && (double) newValue == 0) {
|
||||||
if (item.arrivedProperty().get())
|
if (item.arrivedProperty().get())
|
||||||
showArrivedIcon();
|
showArrivedIcon();
|
||||||
else if (item.storedInMailboxProperty().get())
|
else if (item.storedInMailboxProperty().get())
|
||||||
showMailboxIcon();
|
showMailboxIcon();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
sendMsgProgressIndicator.progressProperty().addListener(sendMsgProgressIndicatorListener);
|
||||||
|
|
||||||
if (item.arrivedProperty().get())
|
if (item.arrivedProperty().get())
|
||||||
showArrivedIcon();
|
showArrivedIcon();
|
||||||
|
@ -527,6 +575,9 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
// TODO There are still some cell rendering issues on updates
|
// TODO There are still some cell rendering issues on updates
|
||||||
setGraphic(messageAnchorPane);
|
setGraphic(messageAnchorPane);
|
||||||
} else {
|
} else {
|
||||||
|
if (sendMsgProgressIndicator != null)
|
||||||
|
sendMsgProgressIndicator.progressProperty().removeListener(sendMsgProgressIndicatorListener);
|
||||||
|
|
||||||
messageAnchorPane.prefWidthProperty().unbind();
|
messageAnchorPane.prefWidthProperty().unbind();
|
||||||
|
|
||||||
AnchorPane.clearConstraints(bg);
|
AnchorPane.clearConstraints(bg);
|
||||||
|
@ -726,18 +777,26 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
||||||
return new TableCell<Dispute, Dispute>() {
|
return new TableCell<Dispute, Dispute>() {
|
||||||
|
|
||||||
|
|
||||||
|
public ReadOnlyBooleanProperty closedProperty;
|
||||||
|
public ChangeListener<Boolean> listener;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateItem(final Dispute item, boolean empty) {
|
public void updateItem(final Dispute item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
if (item != null && !empty) {
|
if (item != null && !empty) {
|
||||||
item.isClosedProperty().addListener((observable, oldValue, newValue) -> {
|
listener = (observable, oldValue, newValue) -> {
|
||||||
setText(newValue ? "Closed" : "Open");
|
setText(newValue ? "Closed" : "Open");
|
||||||
getTableRow().setOpacity(newValue ? 0.4 : 1);
|
getTableRow().setOpacity(newValue ? 0.4 : 1);
|
||||||
});
|
};
|
||||||
|
closedProperty = item.isClosedProperty();
|
||||||
|
closedProperty.addListener(listener);
|
||||||
boolean isClosed = item.isClosed();
|
boolean isClosed = item.isClosed();
|
||||||
setText(isClosed ? "Closed" : "Open");
|
setText(isClosed ? "Closed" : "Open");
|
||||||
getTableRow().setOpacity(isClosed ? 0.4 : 1);
|
getTableRow().setOpacity(isClosed ? 0.4 : 1);
|
||||||
} else {
|
} else {
|
||||||
|
if (closedProperty != null)
|
||||||
|
closedProperty.removeListener(listener);
|
||||||
|
|
||||||
setText("");
|
setText("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import javafx.beans.property.StringProperty;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -58,13 +59,13 @@ public class ReservedListItem {
|
||||||
|
|
||||||
// balance
|
// balance
|
||||||
balanceLabel = new Label();
|
balanceLabel = new Label();
|
||||||
balanceListener = walletService.addBalanceListener(new BalanceListener(getAddress()) {
|
balanceListener = new BalanceListener(getAddress()) {
|
||||||
@Override
|
@Override
|
||||||
public void onBalanceChanged(Coin balance) {
|
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||||
updateBalance(balance);
|
updateBalance(balance);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
walletService.addBalanceListener(balanceListener);
|
||||||
updateBalance(walletService.getBalanceForAddress(getAddress()));
|
updateBalance(walletService.getBalanceForAddress(getAddress()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ import javafx.scene.control.*;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.util.Callback;
|
import javafx.util.Callback;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.core.Transaction;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -95,7 +96,7 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||||
table.getSortOrder().add(dateColumn);
|
table.getSortOrder().add(dateColumn);
|
||||||
balanceListener = new BalanceListener() {
|
balanceListener = new BalanceListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onBalanceChanged(Coin balance) {
|
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||||
updateList();
|
updateList();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -154,13 +154,13 @@ public class TransactionsListItem {
|
||||||
Tooltip.install(progressIndicator, tooltip);
|
Tooltip.install(progressIndicator, tooltip);
|
||||||
|
|
||||||
if (address != null) {
|
if (address != null) {
|
||||||
txConfidenceListener = walletService.addTxConfidenceListener(new TxConfidenceListener(txId) {
|
txConfidenceListener = new TxConfidenceListener(txId) {
|
||||||
@Override
|
@Override
|
||||||
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
|
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
|
||||||
updateConfidence(confidence);
|
updateConfidence(confidence);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
walletService.addTxConfidenceListener(txConfidenceListener);
|
||||||
updateConfidence(transaction.getConfidence());
|
updateConfidence(transaction.getConfidence());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import io.bitsquare.gui.util.BSFormatter;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.core.Transaction;
|
||||||
|
|
||||||
public class WithdrawalListItem {
|
public class WithdrawalListItem {
|
||||||
private final BalanceListener balanceListener;
|
private final BalanceListener balanceListener;
|
||||||
|
@ -42,12 +43,13 @@ public class WithdrawalListItem {
|
||||||
|
|
||||||
// balance
|
// balance
|
||||||
balanceLabel = new Label();
|
balanceLabel = new Label();
|
||||||
balanceListener = walletService.addBalanceListener(new BalanceListener(getAddress()) {
|
balanceListener = new BalanceListener(getAddress()) {
|
||||||
@Override
|
@Override
|
||||||
public void onBalanceChanged(Coin balance) {
|
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||||
updateBalance(balance);
|
updateBalance(balance);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
walletService.addBalanceListener(balanceListener);
|
||||||
|
|
||||||
updateBalance(walletService.getBalanceForAddress(getAddress()));
|
updateBalance(walletService.getBalanceForAddress(getAddress()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
|
|
||||||
balanceListener = new BalanceListener() {
|
balanceListener = new BalanceListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onBalanceChanged(Coin balance) {
|
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||||
updateList();
|
updateList();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,6 +32,7 @@ import io.bitsquare.gui.popups.Popup;
|
||||||
import io.bitsquare.locale.CurrencyUtil;
|
import io.bitsquare.locale.CurrencyUtil;
|
||||||
import io.bitsquare.locale.TradeCurrency;
|
import io.bitsquare.locale.TradeCurrency;
|
||||||
import io.bitsquare.trade.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.scene.control.Tab;
|
import javafx.scene.control.Tab;
|
||||||
import javafx.scene.control.TabPane;
|
import javafx.scene.control.TabPane;
|
||||||
|
@ -46,7 +47,7 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
|
||||||
private TakeOfferView takeOfferView;
|
private TakeOfferView takeOfferView;
|
||||||
private AnchorPane createOfferPane;
|
private AnchorPane createOfferPane;
|
||||||
private AnchorPane takeOfferPane;
|
private AnchorPane takeOfferPane;
|
||||||
private Navigation.Listener listener;
|
private Navigation.Listener navigationListener;
|
||||||
private Offer offer;
|
private Offer offer;
|
||||||
|
|
||||||
private final ViewLoader viewLoader;
|
private final ViewLoader viewLoader;
|
||||||
|
@ -56,6 +57,8 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
|
||||||
private Tab takeOfferTab, createOfferTab, offerBookTab;
|
private Tab takeOfferTab, createOfferTab, offerBookTab;
|
||||||
private TradeCurrency tradeCurrency;
|
private TradeCurrency tradeCurrency;
|
||||||
private boolean createOfferViewOpen, takeOfferViewOpen;
|
private boolean createOfferViewOpen, takeOfferViewOpen;
|
||||||
|
private ChangeListener<Tab> tabChangeListener;
|
||||||
|
private ListChangeListener<Tab> tabListChangeListener;
|
||||||
|
|
||||||
protected OfferView(ViewLoader viewLoader, Navigation navigation, MarketPriceFeed marketPriceFeed) {
|
protected OfferView(ViewLoader viewLoader, Navigation navigation, MarketPriceFeed marketPriceFeed) {
|
||||||
this.viewLoader = viewLoader;
|
this.viewLoader = viewLoader;
|
||||||
|
@ -66,43 +69,32 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initialize() {
|
protected void initialize() {
|
||||||
listener = viewPath -> {
|
navigationListener = viewPath -> {
|
||||||
if (viewPath.size() == 3 && viewPath.indexOf(this.getClass()) == 1)
|
if (viewPath.size() == 3 && viewPath.indexOf(this.getClass()) == 1)
|
||||||
loadView(viewPath.tip());
|
loadView(viewPath.tip());
|
||||||
};
|
};
|
||||||
}
|
tabChangeListener = (observableValue, oldValue, newValue) -> {
|
||||||
|
UserThread.execute(InputTextField::hideErrorMessageDisplay);
|
||||||
@Override
|
if (newValue != null) {
|
||||||
protected void activate() {
|
if (newValue.equals(createOfferTab) && createOfferView != null) {
|
||||||
// We need to remove open validation error popups
|
createOfferView.onTabSelected(true);
|
||||||
// UserThread.execute needed as focus-out event is called after selectedIndexProperty changed
|
} else if (newValue.equals(takeOfferTab) && takeOfferView != null) {
|
||||||
// TODO Find a way to do that in the InputTextField directly, but a tab change does not trigger any event...
|
takeOfferView.onTabSelected(true);
|
||||||
TabPane tabPane = root;
|
} else if (newValue.equals(offerBookTab) && offerBookView != null) {
|
||||||
tabPane.getSelectionModel().selectedItemProperty()
|
offerBookView.onTabSelected(true);
|
||||||
.addListener((observableValue, oldValue, newValue) -> {
|
}
|
||||||
UserThread.execute(InputTextField::hideErrorMessageDisplay);
|
}
|
||||||
if (newValue != null) {
|
if (oldValue != null) {
|
||||||
if (newValue.equals(createOfferTab) && createOfferView != null) {
|
if (oldValue.equals(createOfferTab) && createOfferView != null) {
|
||||||
createOfferView.onTabSelected(true);
|
createOfferView.onTabSelected(false);
|
||||||
} else if (newValue.equals(takeOfferTab) && takeOfferView != null) {
|
} else if (oldValue.equals(takeOfferTab) && takeOfferView != null) {
|
||||||
takeOfferView.onTabSelected(true);
|
takeOfferView.onTabSelected(false);
|
||||||
} else if (newValue.equals(offerBookTab) && offerBookView != null) {
|
} else if (oldValue.equals(offerBookTab) && offerBookView != null) {
|
||||||
offerBookView.onTabSelected(true);
|
offerBookView.onTabSelected(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (oldValue != null) {
|
};
|
||||||
if (oldValue.equals(createOfferTab) && createOfferView != null) {
|
tabListChangeListener = (ListChangeListener<Tab>) change -> {
|
||||||
createOfferView.onTabSelected(false);
|
|
||||||
} else if (oldValue.equals(takeOfferTab) && takeOfferView != null) {
|
|
||||||
takeOfferView.onTabSelected(false);
|
|
||||||
} else if (oldValue.equals(offerBookTab) && offerBookView != null) {
|
|
||||||
offerBookView.onTabSelected(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// We want to get informed when a tab get closed
|
|
||||||
tabPane.getTabs().addListener((ListChangeListener<Tab>) change -> {
|
|
||||||
change.next();
|
change.next();
|
||||||
List<? extends Tab> removedTabs = change.getRemoved();
|
List<? extends Tab> removedTabs = change.getRemoved();
|
||||||
if (removedTabs.size() == 1) {
|
if (removedTabs.size() == 1) {
|
||||||
|
@ -111,17 +103,23 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
|
||||||
else if (removedTabs.get(0).getContent().equals(takeOfferPane))
|
else if (removedTabs.get(0).getContent().equals(takeOfferPane))
|
||||||
onTakeOfferViewRemoved();
|
onTakeOfferViewRemoved();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void activate() {
|
||||||
tradeCurrency = CurrencyUtil.getDefaultTradeCurrency();
|
tradeCurrency = CurrencyUtil.getDefaultTradeCurrency();
|
||||||
|
root.getSelectionModel().selectedItemProperty().addListener(tabChangeListener);
|
||||||
navigation.addListener(listener);
|
root.getTabs().addListener(tabListChangeListener);
|
||||||
|
navigation.addListener(navigationListener);
|
||||||
navigation.navigateTo(MainView.class, this.getClass(), OfferBookView.class);
|
navigation.navigateTo(MainView.class, this.getClass(), OfferBookView.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
navigation.removeListener(listener);
|
navigation.removeListener(navigationListener);
|
||||||
|
root.getSelectionModel().selectedItemProperty().removeListener(tabChangeListener);
|
||||||
|
root.getTabs().removeListener(tabListChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadView(Class<? extends View> viewClass) {
|
private void loadView(Class<? extends View> viewClass) {
|
||||||
|
@ -140,7 +138,7 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
|
||||||
tabPane.getTabs().add(offerBookTab);
|
tabPane.getTabs().add(offerBookTab);
|
||||||
offerBookView = (OfferBookView) view;
|
offerBookView = (OfferBookView) view;
|
||||||
offerBookView.onTabSelected(true);
|
offerBookView.onTabSelected(true);
|
||||||
|
|
||||||
OfferActionHandler offerActionHandler = new OfferActionHandler() {
|
OfferActionHandler offerActionHandler = new OfferActionHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOffer(TradeCurrency tradeCurrency) {
|
public void onCreateOffer(TradeCurrency tradeCurrency) {
|
||||||
|
|
|
@ -46,8 +46,8 @@ import javafx.beans.property.*;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.collections.SetChangeListener;
|
import javafx.collections.SetChangeListener;
|
||||||
import org.bitcoinj.core.*;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.script.Script;
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.bitcoinj.utils.ExchangeRate;
|
import org.bitcoinj.utils.ExchangeRate;
|
||||||
import org.bitcoinj.utils.Fiat;
|
import org.bitcoinj.utils.Fiat;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
@ -102,7 +102,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList();
|
final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList();
|
||||||
|
|
||||||
private PaymentAccount paymentAccount;
|
private PaymentAccount paymentAccount;
|
||||||
private WalletEventListener walletEventListener;
|
|
||||||
private boolean isTabSelected;
|
private boolean isTabSelected;
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,42 +133,36 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
|
|
||||||
balanceListener = new BalanceListener(getAddressEntry().getAddress()) {
|
balanceListener = new BalanceListener(getAddressEntry().getAddress()) {
|
||||||
@Override
|
@Override
|
||||||
public void onBalanceChanged(@NotNull Coin balance) {
|
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||||
updateBalance(balance);
|
updateBalance(balance);
|
||||||
|
|
||||||
|
if (preferences.getBitcoinNetwork() == BitcoinNetwork.MAINNET) {
|
||||||
|
SettableFuture<Coin> future = blockchainService.requestFee(tx.getHashAsString());
|
||||||
|
Futures.addCallback(future, new FutureCallback<Coin>() {
|
||||||
|
public void onSuccess(Coin fee) {
|
||||||
|
UserThread.execute(() -> feeFromFundingTxProperty.set(fee));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFailure(@NotNull Throwable throwable) {
|
||||||
|
UserThread.execute(() -> new Popup()
|
||||||
|
.warning("We did not get a response for the request of the mining fee used " +
|
||||||
|
"in the funding transaction.\n\n" +
|
||||||
|
"Are you sure you used a sufficiently high fee of at least " +
|
||||||
|
formatter.formatCoinWithCode(FeePolicy.getMinRequiredFeeForFundingTx()) + "?")
|
||||||
|
.actionButtonText("Yes, I used a sufficiently high fee.")
|
||||||
|
.onAction(() -> feeFromFundingTxProperty.set(FeePolicy.getMinRequiredFeeForFundingTx()))
|
||||||
|
.closeButtonText("No. Let's cancel that payment.")
|
||||||
|
.onClose(() -> feeFromFundingTxProperty.set(Coin.ZERO))
|
||||||
|
.show());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
feeFromFundingTxProperty.set(FeePolicy.getMinRequiredFeeForFundingTx());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
paymentAccountsChangeListener = change -> paymentAccounts.setAll(user.getPaymentAccounts());
|
paymentAccountsChangeListener = change -> paymentAccounts.setAll(user.getPaymentAccounts());
|
||||||
walletEventListener = new WalletEventListener() {
|
|
||||||
@Override
|
|
||||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
|
||||||
requestFeeFromBlockchain(tx.getHashAsString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReorganize(Wallet wallet) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onWalletChanged(Wallet wallet) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onKeysAdded(List<ECKey> keys) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -203,14 +196,12 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
|
|
||||||
private void addListeners() {
|
private void addListeners() {
|
||||||
walletService.addBalanceListener(balanceListener);
|
walletService.addBalanceListener(balanceListener);
|
||||||
walletService.getWallet().addEventListener(walletEventListener);
|
|
||||||
user.getPaymentAccountsAsObservable().addListener(paymentAccountsChangeListener);
|
user.getPaymentAccountsAsObservable().addListener(paymentAccountsChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void removeListeners() {
|
private void removeListeners() {
|
||||||
walletService.removeBalanceListener(balanceListener);
|
walletService.removeBalanceListener(balanceListener);
|
||||||
walletService.getWallet().removeEventListener(walletEventListener);
|
|
||||||
user.getPaymentAccountsAsObservable().removeListener(paymentAccountsChangeListener);
|
user.getPaymentAccountsAsObservable().removeListener(paymentAccountsChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,9 +272,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doPlaceOffer(Offer offer, TransactionResultHandler resultHandler) {
|
private void doPlaceOffer(Offer offer, TransactionResultHandler resultHandler) {
|
||||||
openOfferManager.onPlaceOffer(offer,
|
openOfferManager.onPlaceOffer(offer, resultHandler);
|
||||||
resultHandler
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
|
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
|
||||||
|
@ -349,25 +338,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
// Utils
|
// Utils
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void requestFeeFromBlockchain(String transactionId) {
|
|
||||||
if (preferences.getBitcoinNetwork() == BitcoinNetwork.MAINNET) {
|
|
||||||
SettableFuture<Coin> future = blockchainService.requestFee(transactionId);
|
|
||||||
Futures.addCallback(future, new FutureCallback<Coin>() {
|
|
||||||
public void onSuccess(Coin fee) {
|
|
||||||
UserThread.execute(() -> feeFromFundingTxProperty.set(fee));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onFailure(@NotNull Throwable throwable) {
|
|
||||||
UserThread.execute(() -> new Popup()
|
|
||||||
.warning("We did not get a response for the request of the mining fee used in the funding transaction.")
|
|
||||||
.show());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
feeFromFundingTxProperty.set(FeePolicy.getMinRequiredFeeForFundingTx());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void calculateVolume() {
|
void calculateVolume() {
|
||||||
if (priceAsFiat.get() != null &&
|
if (priceAsFiat.get() != null &&
|
||||||
amountAsCoin.get() != null &&
|
amountAsCoin.get() != null &&
|
||||||
|
@ -400,6 +370,9 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
|
|
||||||
private void updateBalance(Coin balance) {
|
private void updateBalance(Coin balance) {
|
||||||
isWalletFunded.set(totalToPayAsCoin.get() != null && balance.compareTo(totalToPayAsCoin.get()) >= 0);
|
isWalletFunded.set(totalToPayAsCoin.get() != null && balance.compareTo(totalToPayAsCoin.get()) >= 0);
|
||||||
|
|
||||||
|
if (isWalletFunded.get())
|
||||||
|
walletService.removeBalanceListener(balanceListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Coin getOfferFeeAsCoin() {
|
public Coin getOfferFeeAsCoin() {
|
||||||
|
|
|
@ -451,8 +451,9 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
||||||
if (!model.dataModel.isFeeFromFundingTxSufficient()) {
|
if (!model.dataModel.isFeeFromFundingTxSufficient()) {
|
||||||
new Popup().warning("The mining fee from your funding transaction is not sufficiently high.\n\n" +
|
new Popup().warning("The mining fee from your funding transaction is not sufficiently high.\n\n" +
|
||||||
"You need to use at least a mining fee of " +
|
"You need to use at least a mining fee of " +
|
||||||
model.formatCoin(FeePolicy.getMinRequiredFeeForFundingTx()) + ".\n\n" +
|
model.formatter.formatCoinWithCode(FeePolicy.getMinRequiredFeeForFundingTx()) + ".\n\n" +
|
||||||
"The fee used in your funding transaction was only " + model.formatCoin(newValue) + ".\n\n" +
|
"The fee used in your funding transaction was only " +
|
||||||
|
model.formatter.formatCoinWithCode(newValue) + ".\n\n" +
|
||||||
"The trade transactions might take too much time to be included in " +
|
"The trade transactions might take too much time to be included in " +
|
||||||
"a block if the fee is too low.\n" +
|
"a block if the fee is too low.\n" +
|
||||||
"Please check at your external wallet that you set the required fee and " +
|
"Please check at your external wallet that you set the required fee and " +
|
||||||
|
@ -680,8 +681,9 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
||||||
placeOfferButton.setVisible(false);
|
placeOfferButton.setVisible(false);
|
||||||
placeOfferButton.setOnAction(e -> onPlaceOffer());
|
placeOfferButton.setOnAction(e -> onPlaceOffer());
|
||||||
placeOfferSpinner = placeOfferTuple.second;
|
placeOfferSpinner = placeOfferTuple.second;
|
||||||
|
placeOfferSpinner.setPrefSize(18, 18);
|
||||||
placeOfferSpinnerInfoLabel = placeOfferTuple.third;
|
placeOfferSpinnerInfoLabel = placeOfferTuple.third;
|
||||||
placeOfferSpinnerInfoLabel.setText(BSResources.get("createOffer.fundsBox.placeOfferSpinnerInfo"));
|
placeOfferSpinnerInfoLabel.textProperty().bind(model.placeOfferSpinnerInfoText);
|
||||||
placeOfferSpinnerInfoLabel.setVisible(false);
|
placeOfferSpinnerInfoLabel.setVisible(false);
|
||||||
|
|
||||||
cancelButton2 = addButton(gridPane, ++gridRow, BSResources.get("shared.cancel"));
|
cancelButton2 = addButton(gridPane, ++gridRow, BSResources.get("shared.cancel"));
|
||||||
|
|
|
@ -64,6 +64,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||||
final StringProperty errorMessage = new SimpleStringProperty();
|
final StringProperty errorMessage = new SimpleStringProperty();
|
||||||
final StringProperty btcCode = new SimpleStringProperty();
|
final StringProperty btcCode = new SimpleStringProperty();
|
||||||
final StringProperty tradeCurrencyCode = new SimpleStringProperty();
|
final StringProperty tradeCurrencyCode = new SimpleStringProperty();
|
||||||
|
final StringProperty placeOfferSpinnerInfoText = new SimpleStringProperty();
|
||||||
|
|
||||||
final BooleanProperty isPlaceOfferButtonVisible = new SimpleBooleanProperty(false);
|
final BooleanProperty isPlaceOfferButtonVisible = new SimpleBooleanProperty(false);
|
||||||
final BooleanProperty isPlaceOfferButtonDisabled = new SimpleBooleanProperty(true);
|
final BooleanProperty isPlaceOfferButtonDisabled = new SimpleBooleanProperty(true);
|
||||||
|
@ -105,7 +106,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public CreateOfferViewModel(CreateOfferDataModel dataModel, FiatValidator fiatValidator, BtcValidator btcValidator,
|
public CreateOfferViewModel(CreateOfferDataModel dataModel, FiatValidator fiatValidator, BtcValidator btcValidator,
|
||||||
P2PService p2PService,
|
P2PService p2PService,
|
||||||
BSFormatter formatter) {
|
BSFormatter formatter) {
|
||||||
super(dataModel);
|
super(dataModel);
|
||||||
|
|
||||||
|
@ -231,15 +232,30 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||||
priceAsFiatListener = (ov, oldValue, newValue) -> price.set(formatter.formatFiat(newValue));
|
priceAsFiatListener = (ov, oldValue, newValue) -> price.set(formatter.formatFiat(newValue));
|
||||||
volumeAsFiatListener = (ov, oldValue, newValue) -> volume.set(formatter.formatFiat(newValue));
|
volumeAsFiatListener = (ov, oldValue, newValue) -> volume.set(formatter.formatFiat(newValue));
|
||||||
|
|
||||||
isWalletFundedListener = (ov, oldValue, newValue) -> updateButtonDisableState();
|
isWalletFundedListener = (ov, oldValue, newValue) -> {
|
||||||
feeFromFundingTxListener = (ov, oldValue, newValue) -> updateButtonDisableState();
|
updateButtonDisableState();
|
||||||
|
isPlaceOfferSpinnerVisible.set(true);
|
||||||
|
placeOfferSpinnerInfoText.set("Checking funding tx miner fee...");
|
||||||
|
};
|
||||||
|
feeFromFundingTxListener = (ov, oldValue, newValue) -> {
|
||||||
|
updateButtonDisableState();
|
||||||
|
if (newValue.isPositive()) {
|
||||||
|
isPlaceOfferSpinnerVisible.set(false);
|
||||||
|
placeOfferSpinnerInfoText.set("");
|
||||||
|
}
|
||||||
|
};
|
||||||
requestPlaceOfferSuccessListener = (ov, oldValue, newValue) -> {
|
requestPlaceOfferSuccessListener = (ov, oldValue, newValue) -> {
|
||||||
isPlaceOfferButtonVisible.set(!newValue);
|
if (newValue) {
|
||||||
isPlaceOfferSpinnerVisible.set(false);
|
isPlaceOfferButtonVisible.set(!newValue);
|
||||||
|
isPlaceOfferSpinnerVisible.set(false);
|
||||||
|
placeOfferSpinnerInfoText.set("");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
requestPlaceOfferErrorMessageListener = (ov, oldValue, newValue) -> {
|
requestPlaceOfferErrorMessageListener = (ov, oldValue, newValue) -> {
|
||||||
if (newValue != null)
|
if (newValue != null) {
|
||||||
isPlaceOfferSpinnerVisible.set(false);
|
isPlaceOfferSpinnerVisible.set(false);
|
||||||
|
placeOfferSpinnerInfoText.set("");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,6 +272,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||||
dataModel.minAmountAsCoin.addListener(minAmountAsCoinListener);
|
dataModel.minAmountAsCoin.addListener(minAmountAsCoinListener);
|
||||||
dataModel.priceAsFiat.addListener(priceAsFiatListener);
|
dataModel.priceAsFiat.addListener(priceAsFiatListener);
|
||||||
dataModel.volumeAsFiat.addListener(volumeAsFiatListener);
|
dataModel.volumeAsFiat.addListener(volumeAsFiatListener);
|
||||||
|
|
||||||
dataModel.feeFromFundingTxProperty.addListener(feeFromFundingTxListener);
|
dataModel.feeFromFundingTxProperty.addListener(feeFromFundingTxListener);
|
||||||
dataModel.isWalletFunded.addListener(isWalletFundedListener);
|
dataModel.isWalletFunded.addListener(isWalletFundedListener);
|
||||||
requestPlaceOfferSuccess.addListener(requestPlaceOfferSuccessListener);
|
requestPlaceOfferSuccess.addListener(requestPlaceOfferSuccessListener);
|
||||||
|
@ -275,7 +292,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||||
dataModel.priceAsFiat.removeListener(priceAsFiatListener);
|
dataModel.priceAsFiat.removeListener(priceAsFiatListener);
|
||||||
dataModel.volumeAsFiat.removeListener(volumeAsFiatListener);
|
dataModel.volumeAsFiat.removeListener(volumeAsFiatListener);
|
||||||
|
|
||||||
dataModel.feeFromFundingTxProperty.addListener(feeFromFundingTxListener);
|
dataModel.feeFromFundingTxProperty.removeListener(feeFromFundingTxListener);
|
||||||
dataModel.isWalletFunded.removeListener(isWalletFundedListener);
|
dataModel.isWalletFunded.removeListener(isWalletFundedListener);
|
||||||
requestPlaceOfferSuccess.removeListener(requestPlaceOfferSuccessListener);
|
requestPlaceOfferSuccess.removeListener(requestPlaceOfferSuccessListener);
|
||||||
errorMessage.removeListener(requestPlaceOfferErrorMessageListener);
|
errorMessage.removeListener(requestPlaceOfferErrorMessageListener);
|
||||||
|
@ -302,6 +319,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||||
errorMessage.set(null);
|
errorMessage.set(null);
|
||||||
isPlaceOfferSpinnerVisible.set(true);
|
isPlaceOfferSpinnerVisible.set(true);
|
||||||
requestPlaceOfferSuccess.set(false);
|
requestPlaceOfferSuccess.set(false);
|
||||||
|
placeOfferSpinnerInfoText.set(BSResources.get("createOffer.fundsBox.placeOfferSpinnerInfo"));
|
||||||
|
|
||||||
errorMessageListener = (observable, oldValue, newValue) -> {
|
errorMessageListener = (observable, oldValue, newValue) -> {
|
||||||
if (newValue != null) {
|
if (newValue != null) {
|
||||||
|
@ -315,7 +333,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
offer.errorMessageProperty().addListener(errorMessageListener);
|
offer.errorMessageProperty().addListener(errorMessageListener);
|
||||||
dataModel.onPlaceOffer(offer, (transaction) -> requestPlaceOfferSuccess.set(true));
|
dataModel.onPlaceOffer(offer, transaction -> requestPlaceOfferSuccess.set(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
void onShowPayFundsScreen() {
|
void onShowPayFundsScreen() {
|
||||||
|
|
|
@ -110,6 +110,7 @@ class OfferBookViewModel extends ActivatableViewModel {
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
btcCode.unbind();
|
btcCode.unbind();
|
||||||
|
offerBookListItems.removeListener(listChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,7 +169,6 @@ class OfferBookViewModel extends ActivatableViewModel {
|
||||||
|
|
||||||
public ObservableList<TradeCurrency> getTradeCurrencies() {
|
public ObservableList<TradeCurrency> getTradeCurrencies() {
|
||||||
ObservableList<TradeCurrency> list = preferences.getTradeCurrenciesAsObservable();
|
ObservableList<TradeCurrency> list = preferences.getTradeCurrenciesAsObservable();
|
||||||
/* list.add(0, new AllTradeCurrenciesEntry());*/
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,18 +17,22 @@
|
||||||
|
|
||||||
package io.bitsquare.gui.main.offer.takeoffer;
|
package io.bitsquare.gui.main.offer.takeoffer;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import com.google.common.util.concurrent.SettableFuture;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import io.bitsquare.app.BitsquareApp;
|
import io.bitsquare.app.BitsquareApp;
|
||||||
import io.bitsquare.arbitration.Arbitrator;
|
import io.bitsquare.arbitration.Arbitrator;
|
||||||
import io.bitsquare.btc.AddressEntry;
|
import io.bitsquare.btc.*;
|
||||||
import io.bitsquare.btc.FeePolicy;
|
import io.bitsquare.btc.blockchain.BlockchainService;
|
||||||
import io.bitsquare.btc.TradeWalletService;
|
|
||||||
import io.bitsquare.btc.WalletService;
|
|
||||||
import io.bitsquare.btc.listeners.BalanceListener;
|
import io.bitsquare.btc.listeners.BalanceListener;
|
||||||
import io.bitsquare.btc.pricefeed.MarketPriceFeed;
|
import io.bitsquare.btc.pricefeed.MarketPriceFeed;
|
||||||
|
import io.bitsquare.common.UserThread;
|
||||||
import io.bitsquare.common.handlers.ResultHandler;
|
import io.bitsquare.common.handlers.ResultHandler;
|
||||||
import io.bitsquare.gui.common.model.ActivatableDataModel;
|
import io.bitsquare.gui.common.model.ActivatableDataModel;
|
||||||
|
import io.bitsquare.gui.popups.Popup;
|
||||||
import io.bitsquare.gui.popups.WalletPasswordPopup;
|
import io.bitsquare.gui.popups.WalletPasswordPopup;
|
||||||
|
import io.bitsquare.gui.util.BSFormatter;
|
||||||
import io.bitsquare.locale.TradeCurrency;
|
import io.bitsquare.locale.TradeCurrency;
|
||||||
import io.bitsquare.payment.PaymentAccount;
|
import io.bitsquare.payment.PaymentAccount;
|
||||||
import io.bitsquare.payment.PaymentMethod;
|
import io.bitsquare.payment.PaymentMethod;
|
||||||
|
@ -65,6 +69,8 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
private final WalletPasswordPopup walletPasswordPopup;
|
private final WalletPasswordPopup walletPasswordPopup;
|
||||||
private final Preferences preferences;
|
private final Preferences preferences;
|
||||||
private MarketPriceFeed marketPriceFeed;
|
private MarketPriceFeed marketPriceFeed;
|
||||||
|
private BlockchainService blockchainService;
|
||||||
|
private BSFormatter formatter;
|
||||||
|
|
||||||
private final Coin offerFeeAsCoin;
|
private final Coin offerFeeAsCoin;
|
||||||
private final Coin networkFeeAsCoin;
|
private final Coin networkFeeAsCoin;
|
||||||
|
@ -79,6 +85,7 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
final ObjectProperty<Coin> amountAsCoin = new SimpleObjectProperty<>();
|
final ObjectProperty<Coin> amountAsCoin = new SimpleObjectProperty<>();
|
||||||
final ObjectProperty<Fiat> volumeAsFiat = new SimpleObjectProperty<>();
|
final ObjectProperty<Fiat> volumeAsFiat = new SimpleObjectProperty<>();
|
||||||
final ObjectProperty<Coin> totalToPayAsCoin = new SimpleObjectProperty<>();
|
final ObjectProperty<Coin> totalToPayAsCoin = new SimpleObjectProperty<>();
|
||||||
|
final ObjectProperty<Coin> feeFromFundingTxProperty = new SimpleObjectProperty(Coin.NEGATIVE_SATOSHI);
|
||||||
|
|
||||||
private BalanceListener balanceListener;
|
private BalanceListener balanceListener;
|
||||||
private PaymentAccount paymentAccount;
|
private PaymentAccount paymentAccount;
|
||||||
|
@ -93,7 +100,8 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
@Inject
|
@Inject
|
||||||
TakeOfferDataModel(TradeManager tradeManager, TradeWalletService tradeWalletService,
|
TakeOfferDataModel(TradeManager tradeManager, TradeWalletService tradeWalletService,
|
||||||
WalletService walletService, User user, WalletPasswordPopup walletPasswordPopup,
|
WalletService walletService, User user, WalletPasswordPopup walletPasswordPopup,
|
||||||
Preferences preferences, MarketPriceFeed marketPriceFeed) {
|
Preferences preferences, MarketPriceFeed marketPriceFeed, BlockchainService blockchainService,
|
||||||
|
BSFormatter formatter) {
|
||||||
this.tradeManager = tradeManager;
|
this.tradeManager = tradeManager;
|
||||||
this.tradeWalletService = tradeWalletService;
|
this.tradeWalletService = tradeWalletService;
|
||||||
this.walletService = walletService;
|
this.walletService = walletService;
|
||||||
|
@ -101,6 +109,8 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
this.walletPasswordPopup = walletPasswordPopup;
|
this.walletPasswordPopup = walletPasswordPopup;
|
||||||
this.preferences = preferences;
|
this.preferences = preferences;
|
||||||
this.marketPriceFeed = marketPriceFeed;
|
this.marketPriceFeed = marketPriceFeed;
|
||||||
|
this.blockchainService = blockchainService;
|
||||||
|
this.formatter = formatter;
|
||||||
|
|
||||||
offerFeeAsCoin = FeePolicy.getCreateOfferFee();
|
offerFeeAsCoin = FeePolicy.getCreateOfferFee();
|
||||||
networkFeeAsCoin = FeePolicy.getFixedTxFeeForTrades();
|
networkFeeAsCoin = FeePolicy.getFixedTxFeeForTrades();
|
||||||
|
@ -116,6 +126,12 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
addListeners();
|
addListeners();
|
||||||
updateBalance(walletService.getBalanceForAddress(addressEntry.getAddress()));
|
updateBalance(walletService.getBalanceForAddress(addressEntry.getAddress()));
|
||||||
|
|
||||||
|
// TODO In case that we have funded but restarted, or canceled but took again the offer we would need to
|
||||||
|
// store locally the result when we received the funding tx(s).
|
||||||
|
// For now we just ignore that rare case and bypass the check by setting a sufficient value
|
||||||
|
if (isWalletFunded.get())
|
||||||
|
feeFromFundingTxProperty.set(FeePolicy.getMinRequiredFeeForFundingTx());
|
||||||
|
|
||||||
if (isTabSelected)
|
if (isTabSelected)
|
||||||
marketPriceFeed.setCurrencyCode(offer.getCurrencyCode());
|
marketPriceFeed.setCurrencyCode(offer.getCurrencyCode());
|
||||||
}
|
}
|
||||||
|
@ -153,8 +169,32 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
|
|
||||||
balanceListener = new BalanceListener(addressEntry.getAddress()) {
|
balanceListener = new BalanceListener(addressEntry.getAddress()) {
|
||||||
@Override
|
@Override
|
||||||
public void onBalanceChanged(@NotNull Coin balance) {
|
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||||
updateBalance(balance);
|
updateBalance(balance);
|
||||||
|
|
||||||
|
if (preferences.getBitcoinNetwork() == BitcoinNetwork.MAINNET) {
|
||||||
|
SettableFuture<Coin> future = blockchainService.requestFee(tx.getHashAsString());
|
||||||
|
Futures.addCallback(future, new FutureCallback<Coin>() {
|
||||||
|
public void onSuccess(Coin fee) {
|
||||||
|
UserThread.execute(() -> feeFromFundingTxProperty.set(fee));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFailure(@NotNull Throwable throwable) {
|
||||||
|
UserThread.execute(() -> new Popup()
|
||||||
|
.warning("We did not get a response for the request of the mining fee used " +
|
||||||
|
"in the funding transaction.\n\n" +
|
||||||
|
"Are you sure you used a sufficiently high fee of at least " +
|
||||||
|
formatter.formatCoinWithCode(FeePolicy.getMinRequiredFeeForFundingTx()) + "?")
|
||||||
|
.actionButtonText("Yes, I used a sufficiently high fee.")
|
||||||
|
.onAction(() -> feeFromFundingTxProperty.set(FeePolicy.getMinRequiredFeeForFundingTx()))
|
||||||
|
.closeButtonText("No. Let's cancel that payment.")
|
||||||
|
.onClose(() -> feeFromFundingTxProperty.set(Coin.ZERO))
|
||||||
|
.show());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
feeFromFundingTxProperty.set(FeePolicy.getMinRequiredFeeForFundingTx());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -233,6 +273,10 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
return user.getAcceptedArbitrators().size() > 0;
|
return user.getAcceptedArbitrators().size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isFeeFromFundingTxSufficient() {
|
||||||
|
return feeFromFundingTxProperty.get().compareTo(FeePolicy.getMinRequiredFeeForFundingTx()) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Bindings, listeners
|
// Bindings, listeners
|
||||||
|
@ -279,6 +323,9 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
|
|
||||||
private void updateBalance(@NotNull Coin balance) {
|
private void updateBalance(@NotNull Coin balance) {
|
||||||
isWalletFunded.set(totalToPayAsCoin.get() != null && balance.compareTo(totalToPayAsCoin.get()) >= 0);
|
isWalletFunded.set(totalToPayAsCoin.get() != null && balance.compareTo(totalToPayAsCoin.get()) >= 0);
|
||||||
|
|
||||||
|
if (isWalletFunded.get())
|
||||||
|
walletService.removeBalanceListener(balanceListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isMinAmountLessOrEqualAmount() {
|
boolean isMinAmountLessOrEqualAmount() {
|
||||||
|
|
|
@ -32,6 +32,8 @@ import io.bitsquare.gui.main.MainView;
|
||||||
import io.bitsquare.gui.main.account.AccountView;
|
import io.bitsquare.gui.main.account.AccountView;
|
||||||
import io.bitsquare.gui.main.account.content.arbitratorselection.ArbitratorSelectionView;
|
import io.bitsquare.gui.main.account.content.arbitratorselection.ArbitratorSelectionView;
|
||||||
import io.bitsquare.gui.main.account.settings.AccountSettingsView;
|
import io.bitsquare.gui.main.account.settings.AccountSettingsView;
|
||||||
|
import io.bitsquare.gui.main.funds.FundsView;
|
||||||
|
import io.bitsquare.gui.main.funds.withdrawal.WithdrawalView;
|
||||||
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.pendingtrades.PendingTradesView;
|
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesView;
|
||||||
|
@ -51,6 +53,7 @@ import javafx.scene.layout.*;
|
||||||
import javafx.scene.text.Font;
|
import javafx.scene.text.Font;
|
||||||
import javafx.stage.Window;
|
import javafx.stage.Window;
|
||||||
import javafx.util.StringConverter;
|
import javafx.util.StringConverter;
|
||||||
|
import org.bitcoinj.core.Coin;
|
||||||
import org.controlsfx.control.PopOver;
|
import org.controlsfx.control.PopOver;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
import org.fxmisc.easybind.Subscription;
|
import org.fxmisc.easybind.Subscription;
|
||||||
|
@ -99,6 +102,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||||
private Subscription showCheckAvailabilityPopupSubscription;
|
private Subscription showCheckAvailabilityPopupSubscription;
|
||||||
private SimpleBooleanProperty errorPopupDisplayed;
|
private SimpleBooleanProperty errorPopupDisplayed;
|
||||||
private Popup isOfferAvailablePopup;
|
private Popup isOfferAvailablePopup;
|
||||||
|
private ChangeListener<Coin> feeFromFundingTxListener;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -233,6 +237,30 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||||
paymentAccountsComboBox.setItems(model.getPossiblePaymentAccounts());
|
paymentAccountsComboBox.setItems(model.getPossiblePaymentAccounts());
|
||||||
paymentAccountsComboBox.getSelectionModel().select(0);
|
paymentAccountsComboBox.getSelectionModel().select(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
feeFromFundingTxListener = (observable, oldValue, newValue) -> {
|
||||||
|
log.debug("feeFromFundingTxListener " + newValue);
|
||||||
|
if (!model.dataModel.isFeeFromFundingTxSufficient()) {
|
||||||
|
new Popup().warning("The mining fee from your funding transaction is not sufficiently high.\n\n" +
|
||||||
|
"You need to use at least a mining fee of " +
|
||||||
|
model.formatter.formatCoinWithCode(FeePolicy.getMinRequiredFeeForFundingTx()) + ".\n\n" +
|
||||||
|
"The fee used in your funding transaction was only " +
|
||||||
|
model.formatter.formatCoinWithCode(newValue) + ".\n\n" +
|
||||||
|
"The trade transactions might take too much time to be included in " +
|
||||||
|
"a block if the fee is too low.\n" +
|
||||||
|
"Please check at your external wallet that you set the required fee and " +
|
||||||
|
"do a funding again with the correct fee.\n\n" +
|
||||||
|
"In the \"Funds/Open for withdrawal\" section you can withdraw those funds.")
|
||||||
|
.closeButtonText("Close")
|
||||||
|
.onClose(() -> {
|
||||||
|
close();
|
||||||
|
navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class);
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
model.dataModel.feeFromFundingTxProperty.addListener(feeFromFundingTxListener);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -261,6 +289,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||||
showWarningInvalidBtcDecimalPlacesSubscription.unsubscribe();
|
showWarningInvalidBtcDecimalPlacesSubscription.unsubscribe();
|
||||||
showTransactionPublishedScreenSubscription.unsubscribe();
|
showTransactionPublishedScreenSubscription.unsubscribe();
|
||||||
showCheckAvailabilityPopupSubscription.unsubscribe();
|
showCheckAvailabilityPopupSubscription.unsubscribe();
|
||||||
|
|
||||||
|
model.dataModel.feeFromFundingTxProperty.removeListener(feeFromFundingTxListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -313,8 +343,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||||
public void onTabSelected(boolean isSelected) {
|
public void onTabSelected(boolean isSelected) {
|
||||||
model.dataModel.onTabSelected(isSelected);
|
model.dataModel.onTabSelected(isSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// UI actions
|
// UI actions
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -530,8 +560,9 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||||
takeOfferButton.setVisible(false);
|
takeOfferButton.setVisible(false);
|
||||||
takeOfferButton.setOnAction(e -> onTakeOffer());
|
takeOfferButton.setOnAction(e -> onTakeOffer());
|
||||||
takeOfferSpinner = takeOfferTuple.second;
|
takeOfferSpinner = takeOfferTuple.second;
|
||||||
|
takeOfferSpinner.setPrefSize(18, 18);
|
||||||
takeOfferSpinnerInfoLabel = takeOfferTuple.third;
|
takeOfferSpinnerInfoLabel = takeOfferTuple.third;
|
||||||
takeOfferSpinnerInfoLabel.setText(BSResources.get("takeOffer.fundsBox.takeOfferSpinnerInfo"));
|
takeOfferSpinnerInfoLabel.textProperty().bind(model.takeOfferSpinnerInfoText);
|
||||||
takeOfferSpinnerInfoLabel.setVisible(false);
|
takeOfferSpinnerInfoLabel.setVisible(false);
|
||||||
|
|
||||||
cancelButton2 = addButton(gridPane, ++gridRow, BSResources.get("shared.cancel"));
|
cancelButton2 = addButton(gridPane, ++gridRow, BSResources.get("shared.cancel"));
|
||||||
|
|
|
@ -68,6 +68,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
final StringProperty errorMessage = new SimpleStringProperty();
|
final StringProperty errorMessage = new SimpleStringProperty();
|
||||||
final StringProperty offerWarning = new SimpleStringProperty();
|
final StringProperty offerWarning = new SimpleStringProperty();
|
||||||
final StringProperty btcCode = new SimpleStringProperty();
|
final StringProperty btcCode = new SimpleStringProperty();
|
||||||
|
final StringProperty takeOfferSpinnerInfoText = new SimpleStringProperty();
|
||||||
|
|
||||||
final BooleanProperty isOfferAvailable = new SimpleBooleanProperty();
|
final BooleanProperty isOfferAvailable = new SimpleBooleanProperty();
|
||||||
final BooleanProperty isTakeOfferButtonDisabled = new SimpleBooleanProperty(true);
|
final BooleanProperty isTakeOfferButtonDisabled = new SimpleBooleanProperty(true);
|
||||||
|
@ -89,6 +90,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
private ChangeListener<Offer.State> offerStateListener;
|
private ChangeListener<Offer.State> offerStateListener;
|
||||||
private ChangeListener<String> offerErrorListener;
|
private ChangeListener<String> offerErrorListener;
|
||||||
private ConnectionListener connectionListener;
|
private ConnectionListener connectionListener;
|
||||||
|
private ChangeListener<Coin> feeFromFundingTxListener;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -177,9 +179,9 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
|
|
||||||
void onTakeOffer() {
|
void onTakeOffer() {
|
||||||
takeOfferRequested = true;
|
takeOfferRequested = true;
|
||||||
applyOnTakeOfferResult(false);
|
showTransactionPublishedScreen.set(false);
|
||||||
|
|
||||||
isTakeOfferSpinnerVisible.set(true);
|
isTakeOfferSpinnerVisible.set(true);
|
||||||
|
takeOfferSpinnerInfoText.set(BSResources.get("takeOffer.fundsBox.takeOfferSpinnerInfo"));
|
||||||
dataModel.onTakeOffer(trade -> {
|
dataModel.onTakeOffer(trade -> {
|
||||||
this.trade = trade;
|
this.trade = trade;
|
||||||
trade.stateProperty().addListener(tradeStateListener);
|
trade.stateProperty().addListener(tradeStateListener);
|
||||||
|
@ -328,26 +330,23 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
|| trade.getState() == Trade.State.DEPOSIT_PUBLISHED_MSG_SENT
|
|| trade.getState() == Trade.State.DEPOSIT_PUBLISHED_MSG_SENT
|
||||||
|| trade.getState() == Trade.State.DEPOSIT_PUBLISHED_MSG_RECEIVED) {
|
|| trade.getState() == Trade.State.DEPOSIT_PUBLISHED_MSG_RECEIVED) {
|
||||||
if (trade.getDepositTx() != null)
|
if (trade.getDepositTx() != null)
|
||||||
applyOnTakeOfferResult(true);
|
showTransactionPublishedScreen.set(true);
|
||||||
else
|
else
|
||||||
log.error("trade.getDepositTx() == null. That must not happen");
|
log.error("trade.getDepositTx() == null. That must not happen");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorMessage.get() != null)
|
takeOfferSpinnerInfoText.set("");
|
||||||
|
if (errorMessage.get() == null)
|
||||||
isTakeOfferSpinnerVisible.set(false);
|
isTakeOfferSpinnerVisible.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyOnTakeOfferResult(boolean success) {
|
|
||||||
isTakeOfferSpinnerVisible.set(false);
|
|
||||||
showTransactionPublishedScreen.set(success);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateButtonDisableState() {
|
private void updateButtonDisableState() {
|
||||||
isTakeOfferButtonDisabled.set(!(isBtcInputValid(amount.get()).isValid
|
isTakeOfferButtonDisabled.set(!(isBtcInputValid(amount.get()).isValid
|
||||||
&& dataModel.isMinAmountLessOrEqualAmount()
|
&& dataModel.isMinAmountLessOrEqualAmount()
|
||||||
&& !dataModel.isAmountLargerThanOfferAmount()
|
&& !dataModel.isAmountLargerThanOfferAmount()
|
||||||
&& dataModel.isWalletFunded.get()
|
&& dataModel.isWalletFunded.get()
|
||||||
&& !takeOfferRequested)
|
&& !takeOfferRequested
|
||||||
|
&& dataModel.isFeeFromFundingTxSufficient())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,7 +388,11 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
updateButtonDisableState();
|
updateButtonDisableState();
|
||||||
};
|
};
|
||||||
amountAsCoinListener = (ov, oldValue, newValue) -> amount.set(formatter.formatCoin(newValue));
|
amountAsCoinListener = (ov, oldValue, newValue) -> amount.set(formatter.formatCoin(newValue));
|
||||||
isWalletFundedListener = (ov, oldValue, newValue) -> updateButtonDisableState();
|
isWalletFundedListener = (ov, oldValue, newValue) -> {
|
||||||
|
updateButtonDisableState();
|
||||||
|
isTakeOfferSpinnerVisible.set(true);
|
||||||
|
takeOfferSpinnerInfoText.set("Checking funding tx miner fee...");
|
||||||
|
};
|
||||||
tradeStateListener = (ov, oldValue, newValue) -> applyTradeState(newValue);
|
tradeStateListener = (ov, oldValue, newValue) -> applyTradeState(newValue);
|
||||||
tradeErrorListener = (ov, oldValue, newValue) -> applyTradeErrorMessage(newValue);
|
tradeErrorListener = (ov, oldValue, newValue) -> applyTradeErrorMessage(newValue);
|
||||||
offerStateListener = (ov, oldValue, newValue) -> applyOfferState(newValue);
|
offerStateListener = (ov, oldValue, newValue) -> applyOfferState(newValue);
|
||||||
|
@ -411,6 +414,13 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
public void onError(Throwable throwable) {
|
public void onError(Throwable throwable) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
feeFromFundingTxListener = (ov, oldValue, newValue) -> {
|
||||||
|
updateButtonDisableState();
|
||||||
|
if (newValue.isPositive()) {
|
||||||
|
isTakeOfferSpinnerVisible.set(false);
|
||||||
|
takeOfferSpinnerInfoText.set("");
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addListeners() {
|
private void addListeners() {
|
||||||
|
@ -423,6 +433,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
|
|
||||||
dataModel.isWalletFunded.addListener(isWalletFundedListener);
|
dataModel.isWalletFunded.addListener(isWalletFundedListener);
|
||||||
p2PService.getNetworkNode().addConnectionListener(connectionListener);
|
p2PService.getNetworkNode().addConnectionListener(connectionListener);
|
||||||
|
dataModel.feeFromFundingTxProperty.addListener(feeFromFundingTxListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeListeners() {
|
private void removeListeners() {
|
||||||
|
@ -434,7 +445,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
dataModel.isWalletFunded.removeListener(isWalletFundedListener);
|
dataModel.isWalletFunded.removeListener(isWalletFundedListener);
|
||||||
if (offer != null) {
|
if (offer != null) {
|
||||||
offer.stateProperty().removeListener(offerStateListener);
|
offer.stateProperty().removeListener(offerStateListener);
|
||||||
offer.errorMessageProperty().addListener(offerErrorListener);
|
offer.errorMessageProperty().removeListener(offerErrorListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trade != null) {
|
if (trade != null) {
|
||||||
|
@ -442,6 +453,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
trade.errorMessageProperty().removeListener(tradeErrorListener);
|
trade.errorMessageProperty().removeListener(tradeErrorListener);
|
||||||
}
|
}
|
||||||
p2PService.getNetworkNode().removeConnectionListener(connectionListener);
|
p2PService.getNetworkNode().removeConnectionListener(connectionListener);
|
||||||
|
dataModel.feeFromFundingTxProperty.removeListener(feeFromFundingTxListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -148,20 +148,6 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
||||||
updateSelectedItem();
|
updateSelectedItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSelectedItem() {
|
|
||||||
PendingTradesListItem selectedItem = model.getSelectedItem();
|
|
||||||
if (selectedItem != null) {
|
|
||||||
// Select and focus selectedItem from model
|
|
||||||
int index = table.getItems().indexOf(selectedItem);
|
|
||||||
UserThread.execute(() -> {
|
|
||||||
//TODO app wide focus
|
|
||||||
table.getSelectionModel().select(index);
|
|
||||||
//table.requestFocus();
|
|
||||||
//UserThread.execute(() -> table.getFocusModel().focus(index));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
table.getSelectionModel().selectedItemProperty().removeListener(selectedItemChangeListener);
|
table.getSelectionModel().selectedItemProperty().removeListener(selectedItemChangeListener);
|
||||||
|
@ -183,7 +169,21 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
||||||
scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateSelectedItem() {
|
||||||
|
PendingTradesListItem selectedItem = model.getSelectedItem();
|
||||||
|
if (selectedItem != null) {
|
||||||
|
// Select and focus selectedItem from model
|
||||||
|
int index = table.getItems().indexOf(selectedItem);
|
||||||
|
UserThread.execute(() -> {
|
||||||
|
//TODO app wide focus
|
||||||
|
table.getSelectionModel().select(index);
|
||||||
|
//table.requestFocus();
|
||||||
|
//UserThread.execute(() -> table.getFocusModel().focus(index));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Subviews
|
// Subviews
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -105,13 +105,14 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
timer = FxTimer.runPeriodically(Duration.ofSeconds(1), this::updateTimeLeft);
|
|
||||||
|
|
||||||
tradePeriodStateSubscription = EasyBind.subscribe(trade.getTradePeriodStateProperty(), newValue -> {
|
tradePeriodStateSubscription = EasyBind.subscribe(trade.getTradePeriodStateProperty(), newValue -> {
|
||||||
if (newValue != null) {
|
if (newValue != null) {
|
||||||
updateTradePeriodState(newValue);
|
updateTradePeriodState(newValue);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
timer = FxTimer.runPeriodically(Duration.ofSeconds(1), this::updateTimeLeft);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doDeactivate() {
|
public void doDeactivate() {
|
||||||
|
@ -130,11 +131,11 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
if (tradePeriodStateSubscription != null)
|
if (tradePeriodStateSubscription != null)
|
||||||
tradePeriodStateSubscription.unsubscribe();
|
tradePeriodStateSubscription.unsubscribe();
|
||||||
|
|
||||||
if (notificationGroup != null)
|
|
||||||
notificationGroup.button.setOnAction(null);
|
|
||||||
|
|
||||||
if (timer != null)
|
if (timer != null)
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
|
||||||
|
if (notificationGroup != null)
|
||||||
|
notificationGroup.button.setOnAction(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -32,6 +32,7 @@ import io.bitsquare.gui.util.Transitions;
|
||||||
import io.bitsquare.trade.Contract;
|
import io.bitsquare.trade.Contract;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.binding.ObjectBinding;
|
import javafx.beans.binding.ObjectBinding;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.VPos;
|
import javafx.geometry.VPos;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
|
@ -66,6 +67,10 @@ public class DisputeSummaryPopup extends Popup {
|
||||||
private ToggleGroup feeToggleGroup;
|
private ToggleGroup feeToggleGroup;
|
||||||
private String role;
|
private String role;
|
||||||
private TextArea summaryNotesTextArea;
|
private TextArea summaryNotesTextArea;
|
||||||
|
private ObjectBinding<Tuple2<DisputeResult.FeePaymentPolicy, Toggle>> feePaymentPolicyChanged;
|
||||||
|
private ChangeListener<Tuple2<DisputeResult.FeePaymentPolicy, Toggle>> feePaymentPolicyListener;
|
||||||
|
private ChangeListener<Boolean> shareRadioButtonSelectedListener;
|
||||||
|
private ChangeListener<Toggle> feeToggleSelectionListener;
|
||||||
// keep a reference to not get GCed
|
// keep a reference to not get GCed
|
||||||
|
|
||||||
|
|
||||||
|
@ -106,6 +111,18 @@ public class DisputeSummaryPopup extends Popup {
|
||||||
// Protected
|
// Protected
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanup() {
|
||||||
|
if (feePaymentPolicyChanged != null)
|
||||||
|
feePaymentPolicyChanged.removeListener(feePaymentPolicyListener);
|
||||||
|
|
||||||
|
if (shareRadioButton != null)
|
||||||
|
shareRadioButton.selectedProperty().removeListener(shareRadioButtonSelectedListener);
|
||||||
|
|
||||||
|
if (feeToggleGroup != null)
|
||||||
|
feeToggleGroup.selectedToggleProperty().removeListener(feeToggleSelectionListener);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createGridPane() {
|
protected void createGridPane() {
|
||||||
super.createGridPane();
|
super.createGridPane();
|
||||||
|
@ -164,13 +181,14 @@ public class DisputeSummaryPopup extends Popup {
|
||||||
applyTradeAmountRadioButtonStates();
|
applyTradeAmountRadioButtonStates();
|
||||||
} else {
|
} else {
|
||||||
applyPayoutAmounts(disputeResult.feePaymentPolicyProperty().get(), tradeAmountToggleGroup.selectedToggleProperty().get());
|
applyPayoutAmounts(disputeResult.feePaymentPolicyProperty().get(), tradeAmountToggleGroup.selectedToggleProperty().get());
|
||||||
ObjectBinding<Tuple2<DisputeResult.FeePaymentPolicy, Toggle>> changed = Bindings.createObjectBinding(
|
feePaymentPolicyChanged = Bindings.createObjectBinding(
|
||||||
() -> new Tuple2(disputeResult.feePaymentPolicyProperty().get(), tradeAmountToggleGroup.selectedToggleProperty().get()),
|
() -> new Tuple2(disputeResult.feePaymentPolicyProperty().get(), tradeAmountToggleGroup.selectedToggleProperty().get()),
|
||||||
disputeResult.feePaymentPolicyProperty(),
|
disputeResult.feePaymentPolicyProperty(),
|
||||||
tradeAmountToggleGroup.selectedToggleProperty());
|
tradeAmountToggleGroup.selectedToggleProperty());
|
||||||
changed.addListener((observable, oldValue, newValue) -> {
|
feePaymentPolicyListener = (observable, oldValue, newValue) -> {
|
||||||
applyPayoutAmounts(newValue.first, newValue.second);
|
applyPayoutAmounts(newValue.first, newValue.second);
|
||||||
});
|
};
|
||||||
|
feePaymentPolicyChanged.addListener(feePaymentPolicyListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
setFeeRadioButtonState();
|
setFeeRadioButtonState();
|
||||||
|
@ -242,7 +260,7 @@ public class DisputeSummaryPopup extends Popup {
|
||||||
sellerIsWinnerRadioButton.setToggleGroup(tradeAmountToggleGroup);
|
sellerIsWinnerRadioButton.setToggleGroup(tradeAmountToggleGroup);
|
||||||
shareRadioButton.setToggleGroup(tradeAmountToggleGroup);
|
shareRadioButton.setToggleGroup(tradeAmountToggleGroup);
|
||||||
|
|
||||||
shareRadioButton.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
shareRadioButtonSelectedListener = (observable, oldValue, newValue) -> {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
loserPaysFeeRadioButton.setSelected(false);
|
loserPaysFeeRadioButton.setSelected(false);
|
||||||
|
|
||||||
|
@ -254,7 +272,8 @@ public class DisputeSummaryPopup extends Popup {
|
||||||
}
|
}
|
||||||
|
|
||||||
loserPaysFeeRadioButton.setDisable(newValue);
|
loserPaysFeeRadioButton.setDisable(newValue);
|
||||||
});
|
};
|
||||||
|
shareRadioButton.selectedProperty().addListener(shareRadioButtonSelectedListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFeeControls() {
|
private void addFeeControls() {
|
||||||
|
@ -277,16 +296,15 @@ public class DisputeSummaryPopup extends Popup {
|
||||||
splitFeeRadioButton.setToggleGroup(feeToggleGroup);
|
splitFeeRadioButton.setToggleGroup(feeToggleGroup);
|
||||||
waiveFeeRadioButton.setToggleGroup(feeToggleGroup);
|
waiveFeeRadioButton.setToggleGroup(feeToggleGroup);
|
||||||
|
|
||||||
//setFeeRadioButtonState();
|
feeToggleSelectionListener = (observable, oldValue, newValue) -> {
|
||||||
|
|
||||||
feeToggleGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
|
|
||||||
if (newValue == loserPaysFeeRadioButton)
|
if (newValue == loserPaysFeeRadioButton)
|
||||||
disputeResult.setFeePaymentPolicy(DisputeResult.FeePaymentPolicy.LOSER);
|
disputeResult.setFeePaymentPolicy(DisputeResult.FeePaymentPolicy.LOSER);
|
||||||
else if (newValue == splitFeeRadioButton)
|
else if (newValue == splitFeeRadioButton)
|
||||||
disputeResult.setFeePaymentPolicy(DisputeResult.FeePaymentPolicy.SPLIT);
|
disputeResult.setFeePaymentPolicy(DisputeResult.FeePaymentPolicy.SPLIT);
|
||||||
else if (newValue == waiveFeeRadioButton)
|
else if (newValue == waiveFeeRadioButton)
|
||||||
disputeResult.setFeePaymentPolicy(DisputeResult.FeePaymentPolicy.WAIVE);
|
disputeResult.setFeePaymentPolicy(DisputeResult.FeePaymentPolicy.WAIVE);
|
||||||
});
|
};
|
||||||
|
feeToggleGroup.selectedToggleProperty().addListener(feeToggleSelectionListener);
|
||||||
|
|
||||||
if (dispute.isSupportTicket())
|
if (dispute.isSupportTicket())
|
||||||
feeToggleGroup.selectToggle(waiveFeeRadioButton);
|
feeToggleGroup.selectToggle(waiveFeeRadioButton);
|
||||||
|
|
|
@ -19,6 +19,7 @@ package io.bitsquare.gui.popups;
|
||||||
|
|
||||||
import io.bitsquare.app.BitsquareApp;
|
import io.bitsquare.app.BitsquareApp;
|
||||||
import io.bitsquare.gui.components.InputTextField;
|
import io.bitsquare.gui.components.InputTextField;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
@ -31,6 +32,7 @@ public class EnterPrivKeyPopup extends Popup {
|
||||||
private Button unlockButton;
|
private Button unlockButton;
|
||||||
private InputTextField keyInputTextField;
|
private InputTextField keyInputTextField;
|
||||||
private PrivKeyHandler privKeyHandler;
|
private PrivKeyHandler privKeyHandler;
|
||||||
|
private ChangeListener<String> changeListener;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -47,6 +49,8 @@ public class EnterPrivKeyPopup extends Popup {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public EnterPrivKeyPopup() {
|
public EnterPrivKeyPopup() {
|
||||||
|
if (keyInputTextField != null)
|
||||||
|
keyInputTextField.textProperty().addListener(changeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void show() {
|
public void show() {
|
||||||
|
@ -80,6 +84,10 @@ public class EnterPrivKeyPopup extends Popup {
|
||||||
// Protected
|
// Protected
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanup() {
|
||||||
|
}
|
||||||
|
|
||||||
private void addInputFields() {
|
private void addInputFields() {
|
||||||
Label label = new Label("Enter private key:");
|
Label label = new Label("Enter private key:");
|
||||||
label.setWrapText(true);
|
label.setWrapText(true);
|
||||||
|
@ -92,9 +100,10 @@ public class EnterPrivKeyPopup extends Popup {
|
||||||
GridPane.setMargin(keyInputTextField, new Insets(3, 0, 0, 0));
|
GridPane.setMargin(keyInputTextField, new Insets(3, 0, 0, 0));
|
||||||
GridPane.setRowIndex(keyInputTextField, rowIndex);
|
GridPane.setRowIndex(keyInputTextField, rowIndex);
|
||||||
GridPane.setColumnIndex(keyInputTextField, 1);
|
GridPane.setColumnIndex(keyInputTextField, 1);
|
||||||
keyInputTextField.textProperty().addListener((observable, oldValue, newValue) -> {
|
changeListener = (observable, oldValue, newValue) -> {
|
||||||
unlockButton.setDisable(newValue.length() == 0);
|
unlockButton.setDisable(newValue.length() == 0);
|
||||||
});
|
};
|
||||||
|
keyInputTextField.textProperty().addListener(changeListener);
|
||||||
gridPane.getChildren().addAll(label, keyInputTextField);
|
gridPane.getChildren().addAll(label, keyInputTextField);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,9 +100,15 @@ public class Popup {
|
||||||
stage.hide();
|
stage.hide();
|
||||||
else
|
else
|
||||||
log.warn("Stage is null");
|
log.warn("Stage is null");
|
||||||
|
|
||||||
|
cleanup();
|
||||||
PopupManager.isHidden(this);
|
PopupManager.isHidden(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void cleanup() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public Popup onClose(Runnable closeHandler) {
|
public Popup onClose(Runnable closeHandler) {
|
||||||
this.closeHandlerOptional = Optional.of(closeHandler);
|
this.closeHandlerOptional = Optional.of(closeHandler);
|
||||||
return this;
|
return this;
|
||||||
|
@ -249,7 +255,7 @@ public class Popup {
|
||||||
if (headLine != null) {
|
if (headLine != null) {
|
||||||
headLineLabel = new Label(BSResources.get(headLine));
|
headLineLabel = new Label(BSResources.get(headLine));
|
||||||
headLineLabel.setMouseTransparent(true);
|
headLineLabel.setMouseTransparent(true);
|
||||||
headLineLabel.setStyle("-fx-font-size: 16; -fx-text-fill: #333;");
|
headLineLabel.setId("popup-headline");
|
||||||
GridPane.setHalignment(headLineLabel, HPos.LEFT);
|
GridPane.setHalignment(headLineLabel, HPos.LEFT);
|
||||||
GridPane.setRowIndex(headLineLabel, ++rowIndex);
|
GridPane.setRowIndex(headLineLabel, ++rowIndex);
|
||||||
GridPane.setColumnSpan(headLineLabel, 2);
|
GridPane.setColumnSpan(headLineLabel, 2);
|
||||||
|
@ -271,6 +277,7 @@ public class Popup {
|
||||||
messageLabel = new Label(truncatedMessage);
|
messageLabel = new Label(truncatedMessage);
|
||||||
messageLabel.setMouseTransparent(true);
|
messageLabel.setMouseTransparent(true);
|
||||||
messageLabel.setWrapText(true);
|
messageLabel.setWrapText(true);
|
||||||
|
messageLabel.setId("popup-message");
|
||||||
GridPane.setHalignment(messageLabel, HPos.LEFT);
|
GridPane.setHalignment(messageLabel, HPos.LEFT);
|
||||||
GridPane.setHgrow(messageLabel, Priority.ALWAYS);
|
GridPane.setHgrow(messageLabel, Priority.ALWAYS);
|
||||||
GridPane.setMargin(messageLabel, new Insets(3, 0, 0, 0));
|
GridPane.setMargin(messageLabel, new Insets(3, 0, 0, 0));
|
||||||
|
@ -288,6 +295,7 @@ public class Popup {
|
||||||
"It will make debugging easier if you can attach the bitsquare.log file which you can find in the application directory.");
|
"It will make debugging easier if you can attach the bitsquare.log file which you can find in the application directory.");
|
||||||
|
|
||||||
Button githubButton = new Button("Report to Github issue tracker");
|
Button githubButton = new Button("Report to Github issue tracker");
|
||||||
|
githubButton.setId("popup-button");
|
||||||
GridPane.setMargin(githubButton, new Insets(20, 0, 0, 0));
|
GridPane.setMargin(githubButton, new Insets(20, 0, 0, 0));
|
||||||
GridPane.setHalignment(githubButton, HPos.RIGHT);
|
GridPane.setHalignment(githubButton, HPos.RIGHT);
|
||||||
GridPane.setRowIndex(githubButton, ++rowIndex);
|
GridPane.setRowIndex(githubButton, ++rowIndex);
|
||||||
|
@ -300,6 +308,7 @@ public class Popup {
|
||||||
});
|
});
|
||||||
|
|
||||||
Button mailButton = new Button("Report by email");
|
Button mailButton = new Button("Report by email");
|
||||||
|
mailButton.setId("popup-button");
|
||||||
GridPane.setHalignment(mailButton, HPos.RIGHT);
|
GridPane.setHalignment(mailButton, HPos.RIGHT);
|
||||||
GridPane.setRowIndex(mailButton, ++rowIndex);
|
GridPane.setRowIndex(mailButton, ++rowIndex);
|
||||||
GridPane.setColumnIndex(mailButton, 1);
|
GridPane.setColumnIndex(mailButton, 1);
|
||||||
|
@ -337,6 +346,7 @@ public class Popup {
|
||||||
|
|
||||||
protected void addCloseButton() {
|
protected void addCloseButton() {
|
||||||
closeButton = new Button(closeButtonText == null ? "Close" : closeButtonText);
|
closeButton = new Button(closeButtonText == null ? "Close" : closeButtonText);
|
||||||
|
closeButton.setId("popup-button");
|
||||||
closeButton.setOnAction(event -> {
|
closeButton.setOnAction(event -> {
|
||||||
hide();
|
hide();
|
||||||
closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run());
|
closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run());
|
||||||
|
@ -344,6 +354,7 @@ public class Popup {
|
||||||
|
|
||||||
if (actionHandlerOptional.isPresent() || actionButtonText != null) {
|
if (actionHandlerOptional.isPresent() || actionButtonText != null) {
|
||||||
actionButton = new Button(actionButtonText == null ? "Ok" : actionButtonText);
|
actionButton = new Button(actionButtonText == null ? "Ok" : actionButtonText);
|
||||||
|
actionButton.setId("popup-button");
|
||||||
actionButton.setDefaultButton(true);
|
actionButton.setDefaultButton(true);
|
||||||
//TODO app wide focus
|
//TODO app wide focus
|
||||||
//actionButton.requestFocus();
|
//actionButton.requestFocus();
|
||||||
|
|
|
@ -27,6 +27,7 @@ import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import javafx.beans.property.IntegerProperty;
|
import javafx.beans.property.IntegerProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.TextArea;
|
import javafx.scene.control.TextArea;
|
||||||
|
@ -46,6 +47,8 @@ public class TradeDetailsPopup extends Popup {
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
private DisputeManager disputeManager;
|
private DisputeManager disputeManager;
|
||||||
private Trade trade;
|
private Trade trade;
|
||||||
|
private ChangeListener<Number> changeListener;
|
||||||
|
private TextArea textArea;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -78,6 +81,12 @@ public class TradeDetailsPopup extends Popup {
|
||||||
// Protected
|
// Protected
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanup() {
|
||||||
|
if (textArea != null)
|
||||||
|
textArea.scrollTopProperty().addListener(changeListener);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createGridPane() {
|
protected void createGridPane() {
|
||||||
super.createGridPane();
|
super.createGridPane();
|
||||||
|
@ -173,17 +182,18 @@ public class TradeDetailsPopup extends Popup {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trade.errorMessageProperty().get() != null) {
|
if (trade.errorMessageProperty().get() != null) {
|
||||||
TextArea textArea = addLabelTextArea(gridPane, ++rowIndex, "Error message:", "").second;
|
textArea = addLabelTextArea(gridPane, ++rowIndex, "Error message:", "").second;
|
||||||
textArea.setText(trade.errorMessageProperty().get());
|
textArea.setText(trade.errorMessageProperty().get());
|
||||||
textArea.setEditable(false);
|
textArea.setEditable(false);
|
||||||
|
|
||||||
IntegerProperty count = new SimpleIntegerProperty(20);
|
IntegerProperty count = new SimpleIntegerProperty(20);
|
||||||
int rowHeight = 10;
|
int rowHeight = 10;
|
||||||
textArea.prefHeightProperty().bindBidirectional(count);
|
textArea.prefHeightProperty().bindBidirectional(count);
|
||||||
textArea.scrollTopProperty().addListener((ov, old, newVal) -> {
|
changeListener = (ov, old, newVal) -> {
|
||||||
if (newVal.intValue() > rowHeight)
|
if (newVal.intValue() > rowHeight)
|
||||||
count.setValue(count.get() + newVal.intValue() + 10);
|
count.setValue(count.get() + newVal.intValue() + 10);
|
||||||
});
|
};
|
||||||
|
textArea.scrollTopProperty().addListener(changeListener);
|
||||||
textArea.setScrollTop(30);
|
textArea.setScrollTop(30);
|
||||||
|
|
||||||
TextField state = addLabelTextField(gridPane, ++rowIndex, "Trade state:").second;
|
TextField state = addLabelTextField(gridPane, ++rowIndex, "Trade state:").second;
|
||||||
|
|
|
@ -22,6 +22,7 @@ import io.bitsquare.crypto.ScryptUtil;
|
||||||
import io.bitsquare.gui.components.PasswordTextField;
|
import io.bitsquare.gui.components.PasswordTextField;
|
||||||
import io.bitsquare.gui.util.Transitions;
|
import io.bitsquare.gui.util.Transitions;
|
||||||
import io.bitsquare.gui.util.validation.PasswordValidator;
|
import io.bitsquare.gui.util.validation.PasswordValidator;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
@ -44,6 +45,7 @@ public class WalletPasswordPopup extends Popup {
|
||||||
private Button unlockButton;
|
private Button unlockButton;
|
||||||
private AesKeyHandler aesKeyHandler;
|
private AesKeyHandler aesKeyHandler;
|
||||||
private PasswordTextField passwordTextField;
|
private PasswordTextField passwordTextField;
|
||||||
|
private ChangeListener<String> changeListener;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -59,6 +61,12 @@ public class WalletPasswordPopup extends Popup {
|
||||||
// Public API
|
// Public API
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanup() {
|
||||||
|
if (passwordTextField != null)
|
||||||
|
passwordTextField.textProperty().addListener(changeListener);
|
||||||
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public WalletPasswordPopup(WalletService walletService) {
|
public WalletPasswordPopup(WalletService walletService) {
|
||||||
this.walletService = walletService;
|
this.walletService = walletService;
|
||||||
|
@ -106,9 +114,10 @@ public class WalletPasswordPopup extends Popup {
|
||||||
GridPane.setRowIndex(passwordTextField, rowIndex);
|
GridPane.setRowIndex(passwordTextField, rowIndex);
|
||||||
GridPane.setColumnIndex(passwordTextField, 1);
|
GridPane.setColumnIndex(passwordTextField, 1);
|
||||||
PasswordValidator passwordValidator = new PasswordValidator();
|
PasswordValidator passwordValidator = new PasswordValidator();
|
||||||
passwordTextField.textProperty().addListener((observable, oldValue, newValue) -> {
|
changeListener = (observable, oldValue, newValue) -> {
|
||||||
unlockButton.setDisable(!passwordValidator.validate(newValue).isValid);
|
unlockButton.setDisable(!passwordValidator.validate(newValue).isValid);
|
||||||
});
|
};
|
||||||
|
passwordTextField.textProperty().addListener(changeListener);
|
||||||
gridPane.getChildren().addAll(label, passwordTextField);
|
gridPane.getChildren().addAll(label, passwordTextField);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue