Update to new trade process UI

This commit is contained in:
Manfred Karrer 2014-09-23 22:20:30 +02:00
parent a650aef811
commit f80758ca34
81 changed files with 2785 additions and 1418 deletions

View file

@ -128,6 +128,9 @@ public class BitSquare extends Application {
primaryStage.setMinWidth(750);
primaryStage.setMinHeight(500);
Profiler.initScene(primaryStage.getScene());
primaryStage.show();
} catch (IOException e) {
log.error(e.getMessage());

View file

@ -63,7 +63,7 @@ public class FeePolicy {
try {
return new Address(params, registrationFeeAddress);
} catch (AddressFormatException e) {
e.printStackTrace();
e.printStackTrace();
return null;
}
}*/

View file

@ -18,8 +18,9 @@
package io.bitsquare.btc;
import io.bitsquare.BitSquare;
import io.bitsquare.btc.listeners.AddressConfidenceListener;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.listeners.ConfidenceListener;
import io.bitsquare.btc.listeners.TxConfidenceListener;
import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.persistence.Persistence;
@ -104,7 +105,8 @@ public class WalletFacade {
private final CryptoFacade cryptoFacade;
private final Persistence persistence;
private final List<DownloadListener> downloadListeners = new ArrayList<>();
private final List<ConfidenceListener> confidenceListeners = new ArrayList<>();
private final List<AddressConfidenceListener> addressConfidenceListeners = new ArrayList<>();
private final List<TxConfidenceListener> txConfidenceListeners = new ArrayList<>();
private final List<BalanceListener> balanceListeners = new ArrayList<>();
private Wallet wallet;
private WalletEventListener walletEventListener;
@ -268,13 +270,22 @@ public class WalletFacade {
downloadListeners.remove(listener);
}
public ConfidenceListener addConfidenceListener(ConfidenceListener listener) {
confidenceListeners.add(listener);
public AddressConfidenceListener addAddressConfidenceListener(AddressConfidenceListener listener) {
addressConfidenceListeners.add(listener);
return listener;
}
public void removeConfidenceListener(ConfidenceListener listener) {
confidenceListeners.remove(listener);
public void removeAddressConfidenceListener(AddressConfidenceListener listener) {
addressConfidenceListeners.remove(listener);
}
public TxConfidenceListener addTxConfidenceListener(TxConfidenceListener listener) {
txConfidenceListeners.add(listener);
return listener;
}
public void removeTxConfidenceListener(TxConfidenceListener listener) {
txConfidenceListeners.remove(listener);
}
public BalanceListener addBalanceListener(BalanceListener listener) {
@ -354,16 +365,31 @@ public class WalletFacade {
return getMostRecentConfidence(transactionConfidenceList);
}
private void notifyConfidenceListeners(Transaction tx) {
for (ConfidenceListener confidenceListener : confidenceListeners) {
List<TransactionConfidence> transactionConfidenceList = new ArrayList<>();
transactionConfidenceList.add(getTransactionConfidence(tx, confidenceListener.getAddress()));
TransactionConfidence transactionConfidence = getMostRecentConfidence(transactionConfidenceList);
confidenceListener.onTransactionConfidenceChanged(transactionConfidence);
public TransactionConfidence getConfidenceForTxId(String txId) {
if (wallet != null) {
Set<Transaction> transactions = wallet.getTransactions(true);
for (Transaction tx : transactions) {
if (tx.getHashAsString().equals(txId))
return tx.getConfidence();
}
}
return null;
}
private void notifyConfidenceListeners(Transaction tx) {
for (AddressConfidenceListener addressConfidenceListener : addressConfidenceListeners) {
List<TransactionConfidence> transactionConfidenceList = new ArrayList<>();
transactionConfidenceList.add(getTransactionConfidence(tx, addressConfidenceListener.getAddress()));
TransactionConfidence transactionConfidence = getMostRecentConfidence(transactionConfidenceList);
addressConfidenceListener.onTransactionConfidenceChanged(transactionConfidence);
}
for (TxConfidenceListener txConfidenceListener : txConfidenceListeners) {
if (tx.getHashAsString().equals(txConfidenceListener.getTxID()))
txConfidenceListener.onTransactionConfidenceChanged(tx.getConfidence());
}
}
private TransactionConfidence getTransactionConfidence(Transaction tx, Address address) {
List<TransactionOutput> mergedOutputs = getOutputsWithConnectedOutputs(tx);
@ -924,7 +950,7 @@ public class WalletFacade {
}
// 4 step deposit tx: Offerer send deposit tx to taker
public String takerCommitDepositTx(String depositTxAsHex) {
public Transaction takerCommitDepositTx(String depositTxAsHex) {
log.trace("takerCommitDepositTx");
log.trace("inputs: ");
log.trace("depositTxID=" + depositTxAsHex);
@ -941,7 +967,7 @@ public class WalletFacade {
throw new RuntimeException(e); // Cannot happen, we already called multisigContract.verify()
}
return depositTx.getHashAsString();
return depositTx;
}

View file

@ -20,10 +20,10 @@ package io.bitsquare.btc.listeners;
import com.google.bitcoin.core.Address;
import com.google.bitcoin.core.TransactionConfidence;
public class ConfidenceListener {
public class AddressConfidenceListener {
private final Address address;
public ConfidenceListener(Address address) {
public AddressConfidenceListener(Address address) {
this.address = address;
}

View file

@ -0,0 +1,35 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc.listeners;
import com.google.bitcoin.core.TransactionConfidence;
public class TxConfidenceListener {
private final String txID;
public TxConfidenceListener(String txID) {
this.txID = txID;
}
public String getTxID() {
return txID;
}
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
}
}

View file

@ -178,9 +178,9 @@ public class Navigation {
TAKE_OFFER("/io/bitsquare/gui/main/trade/takeoffer/TakeOfferView.fxml"),
// orders
OFFER("/io/bitsquare/gui/main/orders/offer/OfferView.fxml"),
PENDING_TRADE("/io/bitsquare/gui/main/orders/pending/PendingTradeView.fxml"),
CLOSED_TRADE("/io/bitsquare/gui/main/orders/closed/ClosedTradeView.fxml"),
OFFERS("/io/bitsquare/gui/main/orders/offer/OffersView.fxml"),
PENDING_TRADES("/io/bitsquare/gui/main/orders/pending/PendingTradesView.fxml"),
CLOSED_TRADES("/io/bitsquare/gui/main/orders/closed/ClosedTradesView.fxml"),
// funds
DEPOSIT("/io/bitsquare/gui/main/funds/deposit/DepositView.fxml"),

View file

@ -29,13 +29,6 @@ lower gradient color on tab: dddddd
-fx-focus-color: -fx-accent;
-fx-faint-focus-color: #0f87c322;
-fx-selection-bar: derive(-fx-accent,50%);
/*-fx-hover-base: ladder(
-fx-base,
derive(-fx-base,20%) 20%,
derive(-fx-base,30%) 35%,
derive(-fx-base,40%) 50%
);*/
}
/* Splash */
@ -144,9 +137,9 @@ lower gradient color on tab: dddddd
******************************************************************************/
.tooltip {
-fx-background: rgba(30,30,30);
-fx-background: white;
-fx-text-fill: black;
-fx-background-color: rgba(100,100,100,0.8);
-fx-background-color: white;
-fx-background-radius: 6px;
-fx-background-insets: 0;
-fx-padding: 0.667em 0.75em 0.667em 0.75em; /* 10px */

View file

@ -15,10 +15,9 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components.btc;
package io.bitsquare.gui.components;
import io.bitsquare.gui.OverlayManager;
import io.bitsquare.gui.components.Popups;
import com.google.bitcoin.core.Coin;
import com.google.bitcoin.uri.BitcoinURI;
@ -77,14 +76,13 @@ public class AddressTextField extends AnchorPane {
Desktop.getDesktop().browse(URI.create(getBitcoinURI()));
} catch (IOException e) {
log.warn(e.getMessage());
Popups.openWarningPopup("Information", "Opening a system Bitcoin wallet application has failed. " +
Popups.openWarningPopup("Warning", "Opening a system Bitcoin wallet application has failed. " +
"Perhaps you don't have one installed?");
}
});
addressLabel.focusTraversableProperty().set(focusTraversableProperty().get());
focusedProperty().addListener((ov, oldValue, newValue) -> {
addressLabel.requestFocus();
log.debug("foc");
});
Label copyIcon = new Label();

View file

@ -15,11 +15,11 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components.btc;
package io.bitsquare.gui.components;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.btc.listeners.AddressConfidenceListener;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.listeners.ConfidenceListener;
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator;
import io.bitsquare.gui.util.BSFormatter;
@ -74,7 +74,7 @@ public class BalanceTextField extends AnchorPane {
}
public void setup(WalletFacade walletFacade, Address address) {
walletFacade.addConfidenceListener(new ConfidenceListener(address) {
walletFacade.addAddressConfidenceListener(new AddressConfidenceListener(address) {
@Override
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
updateConfidence(confidence);

View file

@ -134,12 +134,13 @@ public class InfoDisplay extends Parent {
});
sceneProperty().addListener((ov, oldValue, newValue) -> {
if (oldValue == null && newValue != null) {
if (oldValue == null && newValue != null && newValue.getWindow() != null) {
newValue.getWindow().widthProperty().addListener(listener);
// localToScene does deliver 0 instead of the correct x position when scene propery gets set,
// so we delay for 1 render cycle
Platform.runLater(() -> {
label.setVisible(true);
label.prefWidthProperty().unbind();
label.setPrefWidth(newValue.getWindow().getWidth() - localToScene(0, 0).getX() - 35);
});
}

View file

@ -169,6 +169,8 @@ public class Popups {
// Support handling of uncaught exception from any thread (also non gui thread)
public static void handleUncaughtExceptions(Throwable throwable) {
// while dev
log.error(throwable.getMessage());
log.error(throwable.toString());
throwable.printStackTrace();
Runnable runnable = () -> {

View file

@ -0,0 +1,87 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.control.*;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TextFieldWithCopyIcon extends AnchorPane {
private static final Logger log = LoggerFactory.getLogger(TextFieldWithCopyIcon.class);
private final StringProperty text = new SimpleStringProperty();
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public TextFieldWithCopyIcon() {
Label copyIcon = new Label();
copyIcon.setLayoutY(3);
copyIcon.getStyleClass().add("copy-icon");
Tooltip.install(copyIcon, new Tooltip("Copy to clipboard"));
AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY);
AnchorPane.setRightAnchor(copyIcon, 0.0);
copyIcon.setOnMouseClicked(e -> {
if (getText() != null && getText().length() > 0) {
Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent();
content.putString(getText());
clipboard.setContent(content);
}
});
TextField txIdLabel = new TextField();
txIdLabel.setEditable(false);
txIdLabel.textProperty().bindBidirectional(text);
AnchorPane.setRightAnchor(txIdLabel, 30.0);
AnchorPane.setLeftAnchor(txIdLabel, 0.0);
txIdLabel.focusTraversableProperty().set(focusTraversableProperty().get());
focusedProperty().addListener((ov, oldValue, newValue) -> {
txIdLabel.requestFocus();
});
getChildren().addAll(txIdLabel, copyIcon);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter/Setter
///////////////////////////////////////////////////////////////////////////////////////////
public String getText() {
return text.get();
}
public StringProperty textProperty() {
return text;
}
public void setText(String text) {
this.text.set(text);
}
}

View file

@ -0,0 +1,157 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.btc.listeners.TxConfidenceListener;
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator;
import com.google.bitcoin.core.TransactionConfidence;
import java.awt.*;
import java.io.IOException;
import java.net.URI;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.*;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TxIdTextField extends AnchorPane {
private static final Logger log = LoggerFactory.getLogger(TxIdTextField.class);
private final TextField txIdLabel;
private final Tooltip progressIndicatorTooltip;
private final ConfidenceProgressIndicator progressIndicator;
private final Label copyIcon;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public TxIdTextField() {
progressIndicator = new ConfidenceProgressIndicator();
progressIndicator.setFocusTraversable(false);
progressIndicator.setPrefSize(24, 24);
progressIndicator.setId("funds-confidence");
progressIndicator.setLayoutY(1);
progressIndicator.setProgress(0);
progressIndicator.setVisible(false);
AnchorPane.setRightAnchor(progressIndicator, 0.0);
progressIndicatorTooltip = new Tooltip("-");
Tooltip.install(progressIndicator, progressIndicatorTooltip);
copyIcon = new Label();
copyIcon.setLayoutY(3);
copyIcon.getStyleClass().add("copy-icon");
Tooltip.install(copyIcon, new Tooltip("Copy transaction ID to clipboard"));
AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY);
AnchorPane.setRightAnchor(copyIcon, 30.0);
txIdLabel = new TextField();
txIdLabel.setId("address-text-field");
txIdLabel.setEditable(false);
AnchorPane.setRightAnchor(txIdLabel, 55.0);
AnchorPane.setLeftAnchor(txIdLabel, 0.0);
txIdLabel.focusTraversableProperty().set(focusTraversableProperty().get());
focusedProperty().addListener((ov, oldValue, newValue) -> {
txIdLabel.requestFocus();
});
getChildren().addAll(txIdLabel, copyIcon, progressIndicator);
}
public void setup(WalletFacade walletFacade, String txID) {
txIdLabel.setText(txID);
txIdLabel.setOnMouseClicked(mouseEvent -> {
try {
Desktop.getDesktop().browse(URI.create("https://blockchain.info/address/" + txID));
} catch (IOException e) {
log.warn(e.getMessage());
Popups.openWarningPopup("Warning", "Opening blockchain.info failed. Please check your internet " +
"connection.");
}
});
copyIcon.setOnMouseClicked(e -> {
if (txID != null && txID.length() > 0) {
Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent();
content.putString(txID);
clipboard.setContent(content);
}
});
walletFacade.addTxConfidenceListener(new TxConfidenceListener(txID) {
@Override
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
updateConfidence(confidence);
}
});
updateConfidence(walletFacade.getConfidenceForTxId(txID));
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters/Setters
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private void updateConfidence(TransactionConfidence confidence) {
if (confidence != null) {
switch (confidence.getConfidenceType()) {
case UNKNOWN:
progressIndicatorTooltip.setText("Unknown transaction status");
progressIndicator.setProgress(0);
break;
case PENDING:
progressIndicatorTooltip.setText(
"Seen by " + confidence.numBroadcastPeers() + " peer(s) / 0 " + "confirmations");
progressIndicator.setProgress(-1.0);
break;
case BUILDING:
progressIndicatorTooltip.setText("Confirmed in " + confidence.getDepthInBlocks() + " block(s)");
progressIndicator.setProgress(Math.min(1, (double) confidence.getDepthInBlocks() / 6.0));
break;
case DEAD:
progressIndicatorTooltip.setText("Transaction is invalid.");
progressIndicator.setProgress(0);
break;
}
if (progressIndicator.getProgress() != 0) {
progressIndicator.setVisible(true);
AnchorPane.setRightAnchor(progressIndicator, 0.0);
}
}
}
}

View file

@ -0,0 +1,89 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components.processbar;
import java.util.List;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.control.*;
public class ProcessStepBar<T> extends Control {
private List<ProcessStepItem> processStepItems;
private IntegerProperty selectedIndex = new SimpleIntegerProperty(0);
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public ProcessStepBar() {
}
public ProcessStepBar(List<ProcessStepItem> processStepItems) {
this.processStepItems = processStepItems;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Methods
///////////////////////////////////////////////////////////////////////////////////////////
public void next() {
setSelectedIndex(getSelectedIndex() + 1);
}
@Override
protected Skin<?> createDefaultSkin() {
return new ProcessStepBarSkin<>(this);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
public void setProcessStepItems(List<ProcessStepItem> processStepItems) {
this.processStepItems = processStepItems;
if (getSkin() != null)
((ProcessStepBarSkin) getSkin()).setProcessStepItems(processStepItems);
}
public void setSelectedIndex(int selectedIndex) {
this.selectedIndex.set(selectedIndex);
if (getSkin() != null)
((ProcessStepBarSkin) getSkin()).setSelectedIndex(selectedIndex);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public List<ProcessStepItem> getProcessStepItems() {
return processStepItems;
}
public int getSelectedIndex() {
return selectedIndex.get();
}
public IntegerProperty selectedIndexProperty() {
return selectedIndex;
}
}

View file

@ -0,0 +1,235 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components.processbar;
import io.bitsquare.gui.util.Colors;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import com.sun.javafx.scene.control.behavior.BehaviorBase;
import com.sun.javafx.scene.control.behavior.KeyBinding;
import com.sun.javafx.scene.control.skin.BehaviorSkinBase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class ProcessStepBarSkin<T> extends BehaviorSkinBase<ProcessStepBar<T>, BehaviorBase<ProcessStepBar<T>>> {
private static final Logger log = LoggerFactory.getLogger(ProcessStepBarSkin.class);
private final ProcessStepBar<T> controller;
private LabelWithBorder currentLabelWithBorder;
private LabelWithBorder prevLabelWithBorder;
private int index;
private final List<LabelWithBorder> labelWithBorders = new ArrayList<>();
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public ProcessStepBarSkin(final ProcessStepBar<T> control) {
super(control, new BehaviorBase<>(control, Collections.<KeyBinding>emptyList()));
controller = getSkinnable();
setProcessStepItems(controller.getProcessStepItems());
setSelectedIndex(controller.getSelectedIndex());
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
public void setProcessStepItems(List<ProcessStepItem> processStepItems) {
if (processStepItems != null) {
int i = 0;
int size = controller.getProcessStepItems().size();
for (ProcessStepItem processStepItem : controller.getProcessStepItems()) {
LabelWithBorder labelWithBorder = new LabelWithBorder(processStepItem, i == 0, i == size - 1);
getChildren().add(labelWithBorder);
labelWithBorders.add(labelWithBorder);
if (i == 0)
currentLabelWithBorder = prevLabelWithBorder = labelWithBorder;
i++;
}
currentLabelWithBorder.select();
}
}
public void setSelectedIndex(int index) {
this.index = index;
if (index < labelWithBorders.size()) {
for (int i = 0; i <= index; i++) {
if (prevLabelWithBorder != null)
prevLabelWithBorder.deSelect();
currentLabelWithBorder = labelWithBorders.get(i);
currentLabelWithBorder.select();
prevLabelWithBorder = currentLabelWithBorder;
}
}
}
@Override
protected void layoutChildren(double x, double y, double width, double height) {
double distance = 10;
double padding = 50;
for (int i = 0; i < getChildren().size(); i++) {
Node node = getChildren().get(i);
double newWidth = snapSize(node.prefWidth(height)) + padding;
double newHeight = snapSize(node.prefHeight(-1) + 10);
if (i > 0)
x = x - ((LabelWithBorder) node).getArrowWidth();
node.resize(newWidth, newHeight);
// need to add 0.5 to make it sharp
node.relocate(x + 0.5, 0.5);
x += newWidth + distance;
}
}
public static class LabelWithBorder extends Label {
final double borderWidth = 1;
private final double arrowWidth = 10;
private final double arrowHeight = 30;
private final ProcessStepItem processStepItem;
private final boolean isFirst;
private final boolean isLast;
public LabelWithBorder(ProcessStepItem processStepItem, boolean isFirst, boolean isLast) {
super(processStepItem.getLabel());
this.processStepItem = processStepItem;
this.isFirst = isFirst;
this.isLast = isLast;
setAlignment(Pos.CENTER);
setStyle("-fx-font-size: 14");
this.setShape(createButtonShape());
BorderStroke borderStroke = new BorderStroke(Colors.LIGHT_GREY, BorderStrokeStyle.SOLID, null,
new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
this.setBorder(new Border(borderStroke));
setTextFill(Colors.LIGHT_GREY);
}
public void select() {
log.debug("select " + processStepItem.getLabel());
BorderStroke borderStroke = new BorderStroke(Colors.BLUE, BorderStrokeStyle.SOLID, null,
new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
this.setBorder(new Border(borderStroke));
setTextFill(Colors.BLUE);
}
public void deSelect() {
log.debug("deSelect " + processStepItem.getLabel());
BorderStroke borderStroke = new BorderStroke(Colors.GREEN, BorderStrokeStyle.SOLID, null,
new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
this.setBorder(new Border(borderStroke));
setTextFill(Colors.GREEN);
}
public double getArrowWidth() {
return arrowWidth;
}
private Path createButtonShape() {
// build the following shape (or home without left arrow)
// --------
// \ \
// / /
// --------
Path path = new Path();
// begin in the upper left corner
MoveTo e1 = new MoveTo(0, 0);
path.getElements().add(e1);
// draw a horizontal line that defines the width of the shape
HLineTo e2 = new HLineTo();
// bind the width of the shape to the width of the button
e2.xProperty().bind(this.widthProperty().subtract(arrowWidth));
path.getElements().add(e2);
if (!isLast) {
// draw upper part of right arrow
LineTo e3 = new LineTo();
// the x endpoint of this line depends on the x property of line e2
e3.xProperty().bind(e2.xProperty().add(arrowWidth));
e3.setY(arrowHeight / 2.0);
path.getElements().add(e3);
}
// draw lower part of right arrow
LineTo e4 = new LineTo();
// the x endpoint of this line depends on the x property of line e2
e4.xProperty().bind(e2.xProperty());
e4.setY(arrowHeight);
path.getElements().add(e4);
// draw lower horizontal line
HLineTo e5 = new HLineTo(0);
path.getElements().add(e5);
if (!isFirst) {
LineTo e6 = new LineTo(arrowWidth, arrowHeight / 2.0);
path.getElements().add(e6);
}
// close path
ClosePath e7 = new ClosePath();
path.getElements().add(e7);
// this is a dummy color to fill the shape, it won't be visible
path.setFill(Color.BLACK);
return path;
}
@Override
public String toString() {
return "LabelWithBorder{" +
", processStepItem=" + processStepItem +
'}';
}
}
}

View file

@ -0,0 +1,30 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components.processbar;
public class ProcessStepItem {
private final String label;
public ProcessStepItem(String label) {
this.label = label;
}
String getLabel() {
return label;
}
}

View file

@ -141,7 +141,7 @@ public class MainViewCB extends ViewCB<MainPM> {
return childController;
} catch (IOException e) {
e.getStackTrace();
e.printStackTrace();
log.error("Loading view failed. FxmlUrl = " + navigationItem.getFxmlUrl());
}
return null;
@ -191,7 +191,7 @@ public class MainViewCB extends ViewCB<MainPM> {
alertButton.setOnAction((e) ->
navigation.navigationTo(Navigation.Item.MAIN,
Navigation.Item.ORDERS,
Navigation.Item.PENDING_TRADE));
Navigation.Item.PENDING_TRADES));
Tooltip.install(alertButton, new Tooltip("Your offer has been accepted"));
ordersButtonButtonPane.getChildren().add(alertButton);

View file

@ -38,7 +38,7 @@ import javafx.scene.layout.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class AccountViewCB extends CachedViewCB<AccountPM> {
public class AccountViewCB extends CachedViewCB<AccountPM> {
private static final Logger log = LoggerFactory.getLogger(AccountViewCB.class);
@ -125,7 +125,7 @@ class AccountViewCB extends CachedViewCB<AccountPM> {
} catch (IOException e) {
log.error("Loading view failed. FxmlUrl = " + Navigation.Item.ACCOUNT_SETUP.getFxmlUrl());
e.getStackTrace();
e.printStackTrace();
}
return childController;
}

View file

@ -47,7 +47,7 @@
</GridPane.margin>
</ComboBox>
<Label text="Title:" GridPane.rowIndex="1"/>
<Label text="Account name:" GridPane.rowIndex="1"/>
<InputTextField fx:id="titleTextField" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Label text="Holder name:" GridPane.rowIndex="2"/>
@ -72,7 +72,7 @@
visible="false" prefWidth="150.0"/>
</HBox>
<InfoDisplay gridPane="$root" onAction="#onOpenSetupHelp" rowIndex="7"
<InfoDisplay gridPane="$root" onAction="#onOpenSetupHelp" rowIndex="7"
text="The payments account data will be saved in a encrypted form to the Bitcoin block chain and will be used in the trade process for account verification."/>
<HBox fx:id="buttonsHBox" GridPane.columnIndex="1" GridPane.rowIndex="8" spacing="10">

View file

@ -17,8 +17,8 @@
~ along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
-->
<?import io.bitsquare.gui.components.btc.AddressTextField?>
<?import io.bitsquare.gui.components.btc.BalanceTextField?>
<?import io.bitsquare.gui.components.AddressTextField?>
<?import io.bitsquare.gui.components.BalanceTextField?>
<?import io.bitsquare.gui.components.InfoDisplay?>
<?import io.bitsquare.gui.components.TitledGroupBg?>
<?import javafx.geometry.Insets?>

View file

@ -19,9 +19,9 @@ package io.bitsquare.gui.main.account.content.registration;
import io.bitsquare.gui.CachedViewCB;
import io.bitsquare.gui.OverlayManager;
import io.bitsquare.gui.components.AddressTextField;
import io.bitsquare.gui.components.BalanceTextField;
import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.components.btc.AddressTextField;
import io.bitsquare.gui.components.btc.BalanceTextField;
import io.bitsquare.gui.main.account.MultiStepNavigation;
import io.bitsquare.gui.main.account.content.ContextAware;
import io.bitsquare.gui.main.help.Help;

View file

@ -1,68 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.account.settings;
import io.bitsquare.gui.UIModel;
import com.google.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class AccountSettingsModel extends UIModel {
private static final Logger log = LoggerFactory.getLogger(AccountSettingsModel.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private AccountSettingsModel() {
}
///////////////////////////////////////////////////////////////////////////////////////////
// Lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@SuppressWarnings("EmptyMethod")
@Override
public void initialize() {
super.initialize();
}
@Override
public void activate() {
super.activate();
}
@SuppressWarnings("EmptyMethod")
@Override
public void deactivate() {
super.deactivate();
}
@SuppressWarnings("EmptyMethod")
@Override
public void terminate() {
super.terminate();
}
}

View file

@ -1,68 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.account.settings;
import io.bitsquare.gui.PresentationModel;
import com.google.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class AccountSettingsPM extends PresentationModel<AccountSettingsModel> {
private static final Logger log = LoggerFactory.getLogger(AccountSettingsPM.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private AccountSettingsPM(AccountSettingsModel model) {
super(model);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@SuppressWarnings("EmptyMethod")
@Override
public void initialize() {
super.initialize();
}
@Override
public void activate() {
super.activate();
}
@SuppressWarnings("EmptyMethod")
@Override
public void deactivate() {
super.deactivate();
}
@SuppressWarnings("EmptyMethod")
@Override
public void terminate() {
super.terminate();
}
}

View file

@ -46,7 +46,7 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountSettingsViewCB extends CachedViewCB<AccountSettingsPM> {
public class AccountSettingsViewCB extends CachedViewCB {
private static final Logger log = LoggerFactory.getLogger(AccountSettingsViewCB.class);
@ -63,8 +63,8 @@ public class AccountSettingsViewCB extends CachedViewCB<AccountSettingsPM> {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private AccountSettingsViewCB(AccountSettingsPM presentationModel, Navigation navigation) {
super(presentationModel);
private AccountSettingsViewCB(Navigation navigation) {
super();
this.navigation = navigation;
}
@ -156,7 +156,7 @@ public class AccountSettingsViewCB extends CachedViewCB<AccountSettingsPM> {
return childController;
} catch (IOException e) {
log.error("Loading view failed. FxmlUrl = " + navigationItem.getFxmlUrl());
e.getStackTrace();
e.printStackTrace();
}
return null;
}

View file

@ -1,67 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.account.setup;
import io.bitsquare.gui.UIModel;
import com.google.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class AccountSetupModel extends UIModel {
private static final Logger log = LoggerFactory.getLogger(AccountSetupModel.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private AccountSetupModel() {
}
///////////////////////////////////////////////////////////////////////////////////////////
// Lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@SuppressWarnings("EmptyMethod")
@Override
public void initialize() {
super.initialize();
}
@Override
public void activate() {
super.activate();
}
@SuppressWarnings("EmptyMethod")
@Override
public void deactivate() {
super.deactivate();
}
@SuppressWarnings("EmptyMethod")
@Override
public void terminate() {
super.terminate();
}
}

View file

@ -1,68 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.account.setup;
import io.bitsquare.gui.PresentationModel;
import com.google.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class AccountSetupPM extends PresentationModel<AccountSetupModel> {
private static final Logger log = LoggerFactory.getLogger(AccountSetupPM.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private AccountSetupPM(AccountSetupModel model) {
super(model);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@SuppressWarnings("EmptyMethod")
@Override
public void initialize() {
super.initialize();
}
@Override
public void activate() {
super.activate();
}
@SuppressWarnings("EmptyMethod")
@Override
public void deactivate() {
super.deactivate();
}
@SuppressWarnings("EmptyMethod")
@Override
public void terminate() {
super.terminate();
}
}

View file

@ -17,7 +17,6 @@
package io.bitsquare.gui.main.account.setup;
import io.bitsquare.gui.CachedViewCB;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.PresentationModel;
import io.bitsquare.gui.ViewCB;
@ -48,7 +47,10 @@ import javafx.scene.layout.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountSetupViewCB extends CachedViewCB<AccountSetupPM> implements MultiStepNavigation {
/**
* This UI is not cached as it is normally only needed once.
*/
public class AccountSetupViewCB extends ViewCB implements MultiStepNavigation {
private static final Logger log = LoggerFactory.getLogger(AccountSetupViewCB.class);
@ -65,8 +67,8 @@ public class AccountSetupViewCB extends CachedViewCB<AccountSetupPM> implements
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private AccountSetupViewCB(AccountSetupPM presentationModel, Navigation navigation) {
super(presentationModel);
private AccountSetupViewCB(Navigation navigation) {
super();
this.navigation = navigation;
}
@ -102,12 +104,6 @@ public class AccountSetupViewCB extends CachedViewCB<AccountSetupPM> implements
leftVBox.getChildren().addAll(seedWords, password, restrictions, fiatAccount, registration);
super.initialize(url, rb);
}
@Override
public void activate() {
super.activate();
navigation.addListener(listener);
@ -115,17 +111,10 @@ public class AccountSetupViewCB extends CachedViewCB<AccountSetupPM> implements
childController = seedWords.show();
}
@Override
public void deactivate() {
super.deactivate();
navigation.removeListener(listener);
}
@SuppressWarnings("EmptyMethod")
@Override
public void terminate() {
super.terminate();
navigation.removeListener(listener);
}
@ -176,7 +165,7 @@ public class AccountSetupViewCB extends CachedViewCB<AccountSetupPM> implements
return childController;
} catch (IOException e) {
log.error("Loading view failed. FxmlUrl = " + navigationItem.getFxmlUrl());
e.getStackTrace();
e.printStackTrace();
}
return null;
}

View file

@ -49,6 +49,9 @@ import javafx.stage.Stage;
import net.tomp2p.peers.Number640;
import net.tomp2p.storage.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* TODO remove tomp2p dependencies
* import net.tomp2p.peers.Number160;
@ -57,6 +60,8 @@ import net.tomp2p.storage.Data;
* Arbitration is not much developed yet
*/
public class ArbitratorBrowserController extends CachedViewController implements ArbitratorListener {
private static final Logger log = LoggerFactory.getLogger(ArbitratorBrowserController.class);
private final Settings settings;
private final Persistence persistence;

View file

@ -18,7 +18,7 @@
package io.bitsquare.gui.main.funds.transactions;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.btc.listeners.ConfidenceListener;
import io.bitsquare.btc.listeners.AddressConfidenceListener;
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator;
import io.bitsquare.gui.util.BSFormatter;
@ -47,7 +47,7 @@ public class TransactionsListItem {
private final Tooltip tooltip;
private String addressString;
private ConfidenceListener confidenceListener;
private AddressConfidenceListener confidenceListener;
public TransactionsListItem(Transaction transaction, WalletFacade walletFacade) {
this.walletFacade = walletFacade;
@ -135,7 +135,7 @@ public class TransactionsListItem {
Tooltip.install(progressIndicator, tooltip);
if (address != null) {
confidenceListener = walletFacade.addConfidenceListener(new ConfidenceListener(address) {
confidenceListener = walletFacade.addAddressConfidenceListener(new AddressConfidenceListener(address) {
@Override
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
updateConfidence(confidence);
@ -148,7 +148,7 @@ public class TransactionsListItem {
public void cleanup() {
walletFacade.removeConfidenceListener(confidenceListener);
walletFacade.removeAddressConfidenceListener(confidenceListener);
}
private void updateConfidence(TransactionConfidence confidence) {

View file

@ -19,8 +19,8 @@ package io.bitsquare.gui.main.funds.withdrawal;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.btc.listeners.AddressConfidenceListener;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.listeners.ConfidenceListener;
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator;
import com.google.bitcoin.core.Address;
@ -42,7 +42,7 @@ public class WithdrawalListItem {
private final AddressEntry addressEntry;
private final WalletFacade walletFacade;
private final ConfidenceListener confidenceListener;
private final AddressConfidenceListener confidenceListener;
private final ConfidenceProgressIndicator progressIndicator;
@ -63,7 +63,7 @@ public class WithdrawalListItem {
progressIndicator.setPrefSize(24, 24);
Tooltip.install(progressIndicator, tooltip);
confidenceListener = walletFacade.addConfidenceListener(new ConfidenceListener(getAddress()) {
confidenceListener = walletFacade.addAddressConfidenceListener(new AddressConfidenceListener(getAddress()) {
@Override
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
updateConfidence(confidence);
@ -86,7 +86,7 @@ public class WithdrawalListItem {
}
public void cleanup() {
walletFacade.removeConfidenceListener(confidenceListener);
walletFacade.removeAddressConfidenceListener(confidenceListener);
walletFacade.removeBalanceListener(balanceListener);
}

View file

@ -24,6 +24,10 @@ public enum HelpId {
TAKE_OFFER_GENERAL,
TAKE_OFFER_FUNDING,
TAKE_OFFER_ADVANCED,
PENDING_TRADE_OFFERER,
PENDING_TRADE_PAYMENT,
PENDING_TRADE_SUMMARY,
PENDING_TRADE_TAKER,
SETUP_SEED_WORDS,
SETUP_PASSWORD,
SETUP_RESTRICTION_LANGUAGES,

View file

@ -35,9 +35,14 @@ import javafx.scene.*;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// home is just hosting the arbiters buttons yet, but that's just for dev, not clear yet what will be in home,
// probably overview, event history, news, charts,... -> low prio
public class HomeController extends CachedViewCB {
private static final Logger log = LoggerFactory.getLogger(HomeController.class);
private ArbitratorRegistrationController arbitratorRegistrationController;
///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -17,16 +17,15 @@
~ along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
-->
<?import io.bitsquare.gui.components.CachingTabPane?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<CachingTabPane fx:id="root" fx:controller="io.bitsquare.gui.main.orders.OrdersController"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0"
xmlns:fx="http://javafx.com/fxml">
<TabPane fx:id="root" fx:controller="io.bitsquare.gui.main.orders.OrdersViewCB"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0"
xmlns:fx="http://javafx.com/fxml">
<Tab text="Open offers" closable="false"/>
<Tab text="Pending trades" closable="false"/>
<Tab text="Closed trades" closable="false"/>
<Tab fx:id="offersTab" text="Open offers" closable="false"/>
<Tab fx:id="pendingTradesTab" text="Pending trades" closable="false"/>
<Tab fx:id="closedTradesTab" text="Closed trades" closable="false"/>
</CachingTabPane>
</TabPane>

View file

@ -0,0 +1,137 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.orders;
import io.bitsquare.gui.CachedViewCB;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.ViewCB;
import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javax.inject.Inject;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OrdersViewCB extends CachedViewCB {
private static final Logger log = LoggerFactory.getLogger(OrdersViewCB.class);
private Navigation navigation;
private Navigation.Listener listener;
@FXML Tab offersTab, pendingTradesTab, closedTradesTab;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
OrdersViewCB(Navigation navigation) {
super();
this.navigation = navigation;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void initialize(URL url, ResourceBundle rb) {
listener = navigationItems -> {
if (navigationItems != null && navigationItems.length == 3 && navigationItems[1] == Navigation.Item.ORDERS)
loadView(navigationItems[2]);
};
super.initialize(url, rb);
}
@SuppressWarnings("EmptyMethod")
@Override
public void activate() {
super.activate();
navigation.addListener(listener);
navigation.navigationTo(Navigation.Item.MAIN, Navigation.Item.ORDERS, Navigation.Item.PENDING_TRADES);
}
@SuppressWarnings("EmptyMethod")
@Override
public void deactivate() {
super.deactivate();
navigation.removeListener(listener);
}
@SuppressWarnings("EmptyMethod")
@Override
public void terminate() {
super.terminate();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Navigation
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected Initializable loadView(Navigation.Item navigationItem) {
super.loadView(navigationItem);
final ViewLoader loader = new ViewLoader(getClass().getResource(navigationItem.getFxmlUrl()));
try {
GridPane view = loader.load();
Tab tab = null;
switch (navigationItem) {
case OFFERS:
tab = offersTab;
break;
case PENDING_TRADES:
tab = pendingTradesTab;
break;
case CLOSED_TRADES:
tab = closedTradesTab;
break;
}
tab.setContent(view);
((TabPane) root).getSelectionModel().select(tab);
Initializable childController = loader.getController();
((ViewCB) childController).setParent(this);
} catch (IOException e) {
log.error("Loading view failed. FxmlUrl = " + Navigation.Item.ACCOUNT_SETUP.getFxmlUrl());
e.printStackTrace();
}
return childController;
}
}

View file

@ -1,473 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.orders.pending;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.bank.BankAccountType;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.AWTSystemTray;
import io.bitsquare.gui.CachedViewController;
import io.bitsquare.gui.components.ConfidenceDisplay;
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.locale.BSResources;
import io.bitsquare.locale.Country;
import io.bitsquare.trade.Direction;
import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager;
import com.google.bitcoin.core.Coin;
import com.google.bitcoin.core.ECKey;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Wallet;
import com.google.bitcoin.core.WalletEventListener;
import com.google.bitcoin.script.Script;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.ResourceBundle;
import javax.inject.Inject;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.util.Callback;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PendingTradeController extends CachedViewController {
private static final Logger log = LoggerFactory.getLogger(PendingTradeController.class);
private final TradeManager tradeManager;
private final WalletFacade walletFacade;
private Trade currentTrade;
private ConfidenceDisplay confidenceDisplay;
@FXML TableView openTradesTable;
@FXML TableColumn<String, PendingTradesListItem> directionColumn, countryColumn, bankAccountTypeColumn,
priceColumn, amountColumn, volumeColumn, statusColumn, selectColumn;
@FXML ConfidenceProgressIndicator progressIndicator;
@FXML Label txTitleLabel, txHeaderLabel, confirmationLabel, txIDCopyIcon, holderNameCopyIcon,
primaryBankAccountIDCopyIcon, secondaryBankAccountIDCopyIcon, bankAccountDetailsHeaderLabel,
bankAccountTypeTitleLabel, holderNameTitleLabel, primaryBankAccountIDTitleLabel,
secondaryBankAccountIDTitleLabel;
@FXML TextField txTextField, bankAccountTypeTextField, holderNameTextField, primaryBankAccountIDTextField,
secondaryBankAccountIDTextField;
@FXML Button bankTransferInitedButton;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public PendingTradeController(TradeManager tradeManager, WalletFacade walletFacade) {
this.tradeManager = tradeManager;
this.walletFacade = walletFacade;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void initialize(URL url, ResourceBundle rb) {
super.initialize(url, rb);
}
@Override
public void deactivate() {
super.deactivate();
}
@Override
public void activate() {
super.activate();
Map<String, Trade> trades = tradeManager.getTrades();
List<Trade> tradeList = new ArrayList<>(trades.values());
ObservableList<PendingTradesListItem> tradeItems = FXCollections.observableArrayList();
for (Iterator<Trade> iterator = tradeList.iterator(); iterator.hasNext(); ) {
Trade trade = iterator.next();
tradeItems.add(new PendingTradesListItem(trade));
}
setCountryColumnCellFactory();
setBankAccountTypeColumnCellFactory();
setDirectionColumnCellFactory();
setSelectColumnCellFactory();
openTradesTable.setItems(tradeItems);
openTradesTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
openTradesTable.getSelectionModel().selectedItemProperty().addListener((obsValue, oldValue, newValue) -> {
if (newValue instanceof PendingTradesListItem) {
showTradeDetails((PendingTradesListItem) newValue);
}
});
tradeManager.getNewTradeProperty().addListener((observableValue, oldTradeId, newTradeId) -> {
Trade newTrade = tradeManager.getTrade(newTradeId);
if (newTrade != null) {
tradeItems.add(new PendingTradesListItem(newTrade));
}
});
initCopyIcons();
// select
Optional<PendingTradesListItem> currentTradeItemOptional = tradeItems.stream().filter((e) ->
tradeManager.getPendingTrade() != null &&
e.getTrade().getId().equals(tradeManager.getPendingTrade().getId())).findFirst();
if (currentTradeItemOptional.isPresent()) {
openTradesTable.getSelectionModel().select(currentTradeItemOptional.get());
}
tradeItems.addListener((ListChangeListener<PendingTradesListItem>) change -> {
if (openTradesTable.getSelectionModel().getSelectedItem() == null && tradeItems.size() > 0) {
openTradesTable.getSelectionModel().select(0);
}
});
}
///////////////////////////////////////////////////////////////////////////////////////////
// GUI handlers
///////////////////////////////////////////////////////////////////////////////////////////
public void bankTransferInited() {
tradeManager.bankTransferInited(currentTrade.getId());
bankTransferInitedButton.setDisable(true);
}
public void close() {
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////////////////////////////////
private void showTradeDetails(PendingTradesListItem tradesTableItem) {
fillData(tradesTableItem.getTrade());
}
private void updateTx(Transaction transaction) {
txTextField.setText(transaction.getHashAsString());
confidenceDisplay =
new ConfidenceDisplay(walletFacade.getWallet(), confirmationLabel, transaction, progressIndicator);
int depthInBlocks = transaction.getConfidence().getDepthInBlocks();
bankTransferInitedButton.setDisable(depthInBlocks == 0);
walletFacade.getWallet().addEventListener(new WalletEventListener() {
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
int depthInBlocks = tx.getConfidence().getDepthInBlocks();
bankTransferInitedButton.setDisable(depthInBlocks == 0);
}
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
}
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
}
@Override
public void onReorganize(Wallet wallet) {
}
@Override
public void onWalletChanged(Wallet wallet) {
}
@Override
public void onScriptsAdded(Wallet wallet, List<Script> scripts) {
}
@Override
public void onKeysAdded(List<ECKey> keys) {
}
});
}
private void fillData(Trade trade) {
currentTrade = trade;
Transaction transaction = trade.getDepositTransaction();
if (transaction == null) {
trade.depositTxChangedProperty().addListener((observableValue, aBoolean, aBoolean2) ->
updateTx(trade.getDepositTransaction()));
}
else {
updateTx(trade.getDepositTransaction());
}
// back details
if (trade.getContract() != null) {
setBankData(trade);
}
else {
trade.contractChangedProperty().addListener((observableValue, aBoolean, aBoolean2) -> setBankData(trade));
}
// state
trade.stateChangedProperty().addListener((observableValue, aString, aString2) -> setState(trade));
}
private void setState(Trade trade) {
if (trade.getState() == Trade.State.COMPLETED) {
Transaction transaction = trade.getPayoutTransaction();
confidenceDisplay.destroy();
confidenceDisplay =
new ConfidenceDisplay(walletFacade.getWallet(), confirmationLabel, transaction, progressIndicator);
txTextField.setText(transaction.getHashAsString());
txHeaderLabel.setText("Payout transaction");
txTitleLabel.setText("Payout transaction ID:");
bankAccountDetailsHeaderLabel.setText("Summary");
bankAccountTypeTitleLabel.setText("You have bought:");
holderNameTitleLabel.setText("You have payed (" + trade.getOffer().getCurrency() + "):");
primaryBankAccountIDTitleLabel.setText("Total fees (offer fee + tx fee):");
secondaryBankAccountIDTitleLabel.setText("Refunded collateral:");
bankAccountTypeTextField.setText(BSFormatter.formatCoinWithCode(trade.getTradeAmount()));
holderNameTextField.setText(BSFormatter.formatFiat(trade.getTradeVolume()));
primaryBankAccountIDTextField.setText(
BSFormatter.formatCoinWithCode(FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE)));
secondaryBankAccountIDTextField.setText(BSFormatter.formatCoinWithCode(trade.getCollateralAmount()));
holderNameCopyIcon.setVisible(false);
primaryBankAccountIDCopyIcon.setVisible(false);
secondaryBankAccountIDCopyIcon.setVisible(false);
bankTransferInitedButton.setVisible(false);
AWTSystemTray.setIcon();
}
}
private void setBankData(Trade trade) {
BankAccount bankAccount = trade.getContract().getTakerBankAccount();
bankAccountTypeTextField.setText(bankAccount.getBankAccountType().toString());
holderNameTextField.setText(bankAccount.getAccountHolderName());
primaryBankAccountIDTextField.setText(bankAccount.getAccountPrimaryID());
secondaryBankAccountIDTextField.setText(bankAccount.getAccountSecondaryID());
}
private void initCopyIcons() {
AwesomeDude.setIcon(txIDCopyIcon, AwesomeIcon.COPY);
txIDCopyIcon.setOnMouseClicked(e -> {
Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent();
content.putString(txTextField.getText());
clipboard.setContent(content);
});
AwesomeDude.setIcon(holderNameCopyIcon, AwesomeIcon.COPY);
holderNameCopyIcon.setOnMouseClicked(e -> {
Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent();
content.putString(holderNameTextField.getText());
clipboard.setContent(content);
});
AwesomeDude.setIcon(primaryBankAccountIDCopyIcon, AwesomeIcon.COPY);
primaryBankAccountIDCopyIcon.setOnMouseClicked(e -> {
Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent();
content.putString(primaryBankAccountIDTextField.getText());
clipboard.setContent(content);
});
AwesomeDude.setIcon(secondaryBankAccountIDCopyIcon, AwesomeIcon.COPY);
secondaryBankAccountIDCopyIcon.setOnMouseClicked(e -> {
Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent();
content.putString(secondaryBankAccountIDTextField.getText());
clipboard.setContent(content);
});
}
///////////////////////////////////////////////////////////////////////////////////////////
// Table columns
///////////////////////////////////////////////////////////////////////////////////////////
private void setCountryColumnCellFactory() {
countryColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue()));
countryColumn.setCellFactory(
new Callback<TableColumn<String, PendingTradesListItem>, TableCell<String, PendingTradesListItem>>() {
@Override
public TableCell<String, PendingTradesListItem> call(
TableColumn<String, PendingTradesListItem> directionColumn) {
return new TableCell<String, PendingTradesListItem>() {
final HBox hBox = new HBox();
{
hBox.setSpacing(3);
hBox.setAlignment(Pos.CENTER);
setGraphic(hBox);
}
@Override
public void updateItem(final PendingTradesListItem tradesTableItem, boolean empty) {
super.updateItem(tradesTableItem, empty);
hBox.getChildren().clear();
if (tradesTableItem != null) {
Country country = tradesTableItem.getTrade().getOffer().getBankAccountCountry();
hBox.getChildren().add(ImageUtil.getCountryIconImageView(country));
Tooltip.install(this, new Tooltip(country.getName()));
}
}
};
}
});
}
private void setBankAccountTypeColumnCellFactory() {
bankAccountTypeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue()));
bankAccountTypeColumn.setCellFactory(
new Callback<TableColumn<String, PendingTradesListItem>, TableCell<String, PendingTradesListItem>>() {
@Override
public TableCell<String, PendingTradesListItem> call(
TableColumn<String, PendingTradesListItem> directionColumn) {
return new TableCell<String, PendingTradesListItem>() {
@Override
public void updateItem(final PendingTradesListItem tradesTableItem, boolean empty) {
super.updateItem(tradesTableItem, empty);
if (tradesTableItem != null) {
BankAccountType bankAccountType = tradesTableItem.getTrade().getOffer()
.getBankAccountType();
setText(BSResources.get(bankAccountType.toString()));
}
else {
setText("");
}
}
};
}
});
}
private void setDirectionColumnCellFactory() {
directionColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue()));
directionColumn.setCellFactory(
new Callback<TableColumn<String, PendingTradesListItem>, TableCell<String, PendingTradesListItem>>() {
@Override
public TableCell<String, PendingTradesListItem> call(
TableColumn<String, PendingTradesListItem> directionColumn) {
return new TableCell<String, PendingTradesListItem>() {
final ImageView iconView = new ImageView();
final Button button = new Button();
{
button.setGraphic(iconView);
button.setMinWidth(70);
}
@Override
public void updateItem(final PendingTradesListItem tradesTableItem, boolean empty) {
super.updateItem(tradesTableItem, empty);
if (tradesTableItem != null) {
String title;
Offer offer = tradesTableItem.getTrade().getOffer();
if (offer.getDirection() == Direction.SELL) {
iconView.setId("image-buy");
title = BSFormatter.formatDirection(Direction.BUY, true);
}
else {
iconView.setId("image-sell");
title = BSFormatter.formatDirection(Direction.SELL, true);
}
button.setDisable(true);
button.setText(title);
setGraphic(button);
}
else {
setGraphic(null);
}
}
};
}
});
}
private void setSelectColumnCellFactory() {
selectColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue()));
selectColumn.setCellFactory(
new Callback<TableColumn<String, PendingTradesListItem>, TableCell<String, PendingTradesListItem>>() {
@Override
public TableCell<String, PendingTradesListItem> call(
TableColumn<String, PendingTradesListItem> directionColumn) {
return new TableCell<String, PendingTradesListItem>() {
final Button button = new Button("Select");
@Override
public void updateItem(final PendingTradesListItem tradesTableItem, boolean empty) {
super.updateItem(tradesTableItem, empty);
if (tradesTableItem != null) {
button.setOnAction(event -> showTradeDetails(tradesTableItem));
setGraphic(button);
}
else {
setGraphic(null);
}
}
};
}
});
}
}

View file

@ -1,178 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ This file is part of Bitsquare.
~
~ Bitsquare is free software: you can redistribute it and/or modify it
~ under the terms of the GNU Affero General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or (at
~ your option) any later version.
~
~ Bitsquare is distributed in the hope that it will be useful, but WITHOUT
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
~ License for more details.
~
~ You should have received a copy of the GNU Affero General Public License
~ along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
-->
<?import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.*?>
<?import javafx.scene.layout.*?>
<VBox fx:id="root" fx:controller="io.bitsquare.gui.main.orders.pending.PendingTradeController"
spacing="10" AnchorPane.bottomAnchor="0"
AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0" AnchorPane.topAnchor="0"
xmlns:fx="http://javafx.com/fxml">
<TableView id="orderbook-table" fx:id="openTradesTable" prefHeight="150.0">
<columns>
<TableColumn fx:id="amountColumn" minWidth="120" text="Amount in BTC (Min.)">
<cellValueFactory>
<PropertyValueFactory property="amount"/>
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="priceColumn" minWidth="70" text="Price">
<cellValueFactory>
<PropertyValueFactory property="price"/>
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="volumeColumn" minWidth="130" text="Amount in EUR (Min.)">
<cellValueFactory>
<PropertyValueFactory property="volume"/>
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="countryColumn" minWidth="60" text="Country"/>
<TableColumn fx:id="bankAccountTypeColumn" minWidth="140" text="Bank transfer type"/>
<TableColumn fx:id="directionColumn" minWidth="80" sortable="false" text="Offer type"/>
<TableColumn fx:id="statusColumn" minWidth="80" text="Status">
<cellValueFactory>
<PropertyValueFactory property="status"/>
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="selectColumn" minWidth="60" sortable="false" text=""/>
</columns>
<VBox.margin>
<Insets left="10.0" right="10.0"/>
</VBox.margin>
</TableView>
<Label text="After you received 1 blockchain confirmation you are safe to start the bank transfer.">
<VBox.margin>
<Insets bottom="10.0" left="10.0" top="10.0"/>
</VBox.margin>
</Label>
<GridPane hgap="5.0" vgap="5.0">
<!-- row 0 -->
<Label fx:id="txHeaderLabel" id="form-header-text" text="Deposit transaction" GridPane.columnSpan="2"
GridPane.halignment="LEFT"/>
<!-- row 1 -->
<Label fx:id="txTitleLabel" text="Deposit transaction ID:" GridPane.rowIndex="1"/>
<TextField fx:id="txTextField" editable="false" focusTraversable="false" GridPane.columnIndex="1"
GridPane.rowIndex="1"/>
<Label fx:id="txIDCopyIcon" id="copy-icon" minWidth="10" GridPane.columnIndex="2" GridPane.rowIndex="1">
<padding>
<Insets bottom="0.0" left="0.0" right="0.0" top="-1.0"/>
</padding>
<tooltip>
<Tooltip text="Copy address to clipboard"/>
</tooltip>
</Label>
<ConfidenceProgressIndicator fx:id="progressIndicator" visible="false" progress="0" GridPane.columnIndex="3"
GridPane.halignment="LEFT" GridPane.rowIndex="1"
GridPane.rowSpan="2" GridPane.valignment="TOP">
<GridPane.margin>
<Insets top="2.0"/>
</GridPane.margin>
</ConfidenceProgressIndicator>
<Label fx:id="confirmationLabel" visible="false" GridPane.columnIndex="4" GridPane.rowIndex="1"/>
<!-- row 2 -->
<Label fx:id="bankAccountDetailsHeaderLabel" id="form-header-text" text="Bank details" GridPane.columnIndex="0"
GridPane.columnSpan="2" GridPane.halignment="LEFT"
GridPane.rowIndex="2"/>
<!-- row 3 -->
<Label fx:id="bankAccountTypeTitleLabel" text="Bank account type:" GridPane.columnIndex="0"
GridPane.rowIndex="3"/>
<TextField fx:id="bankAccountTypeTextField" editable="false" focusTraversable="false" GridPane.columnIndex="1"
GridPane.rowIndex="3"/>
<!-- row 4 -->
<Label fx:id="holderNameTitleLabel" text="Holder name:" GridPane.columnIndex="0" GridPane.rowIndex="4"/>
<TextField fx:id="holderNameTextField" editable="false" focusTraversable="false" GridPane.columnIndex="1"
GridPane.rowIndex="4"/>
<Label fx:id="holderNameCopyIcon" id="copy-icon" minWidth="10" GridPane.columnIndex="2" GridPane.rowIndex="4">
<padding>
<Insets bottom="0.0" left="0.0" right="0.0" top="-1.0"/>
</padding>
<tooltip>
<Tooltip text="Copy address to clipboard"/>
</tooltip>
</Label>
<!-- row 5 -->
<Label fx:id="primaryBankAccountIDTitleLabel" text="Primary bank account ID:" GridPane.columnIndex="0"
GridPane.rowIndex="5"/>
<TextField fx:id="primaryBankAccountIDTextField" editable="false" focusTraversable="false"
GridPane.columnIndex="1" GridPane.rowIndex="5"/>
<Label fx:id="primaryBankAccountIDCopyIcon" id="copy-icon" minWidth="10" GridPane.columnIndex="2"
GridPane.rowIndex="5">
<padding>
<Insets bottom="0.0" left="0.0" right="0.0" top="-1.0"/>
</padding>
<tooltip>
<Tooltip text="Copy address to clipboard"/>
</tooltip>
</Label>
<!-- row 6 -->
<Label fx:id="secondaryBankAccountIDTitleLabel" text="Secondary bank account ID:" GridPane.columnIndex="0"
GridPane.rowIndex="6"/>
<TextField fx:id="secondaryBankAccountIDTextField" editable="false" focusTraversable="false"
GridPane.columnIndex="1" GridPane.rowIndex="6"/>
<Label fx:id="secondaryBankAccountIDCopyIcon" id="copy-icon" minWidth="10" GridPane.columnIndex="2"
GridPane.rowIndex="6">
<padding>
<Insets bottom="0.0" left="0.0" right="0.0" top="-1.0"/>
</padding>
<tooltip>
<Tooltip text="Copy address to clipboard"/>
</tooltip>
</Label>
<!-- row 7 -->
<Button fx:id="bankTransferInitedButton" defaultButton="true" onAction="#bankTransferInited" disable="true"
text="Bank transfer initiated"
GridPane.columnIndex="1"
GridPane.rowIndex="7"/>
<columnConstraints>
<ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES"/>
<ColumnConstraints hgrow="ALWAYS"/>
<ColumnConstraints fillWidth="false" hgrow="SOMETIMES" minWidth="20"/>
<ColumnConstraints fillWidth="false" hgrow="SOMETIMES" minWidth="20" prefWidth="20"/>
<ColumnConstraints fillWidth="false" hgrow="SOMETIMES"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
<RowConstraints/>
</rowConstraints>
<VBox.margin>
<Insets left="10.0" right="10.0"/>
</VBox.margin>
</GridPane>
</VBox>

View file

@ -0,0 +1,201 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.orders.pending;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.btc.listeners.TxConfidenceListener;
import io.bitsquare.gui.UIModel;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager;
import com.google.bitcoin.core.Coin;
import com.google.bitcoin.core.TransactionConfidence;
import com.google.inject.Inject;
import java.util.Optional;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PendingTradesModel extends UIModel {
private static final Logger log = LoggerFactory.getLogger(PendingTradesModel.class);
private final TradeManager tradeManager;
private WalletFacade walletFacade;
private final ObservableList<PendingTradesListItem> pendingTrades = FXCollections.observableArrayList();
private PendingTradesListItem currentItem;
private boolean isOfferer;
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
final ObjectProperty<Trade.State> tradeState = new SimpleObjectProperty<>();
final ObjectProperty<Throwable> fault = new SimpleObjectProperty<>();
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public PendingTradesModel(TradeManager tradeManager, WalletFacade walletFacade) {
this.tradeManager = tradeManager;
this.walletFacade = walletFacade;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void initialize() {
super.initialize();
// transform trades to list of PendingTradesListItems and keep it updated
tradeManager.getTrades().values().stream().forEach(e -> pendingTrades.add(new PendingTradesListItem(e)));
tradeManager.getTrades().addListener((MapChangeListener<String, Trade>) change -> {
if (change.wasAdded())
pendingTrades.add(new PendingTradesListItem(change.getValueAdded()));
else if (change.wasAdded())
pendingTrades.remove(new PendingTradesListItem(change.getValueRemoved()));
});
}
@Override
public void activate() {
super.activate();
// TODO Check if we can really use tradeManager.getPendingTrade()
Optional<PendingTradesListItem> currentTradeItemOptional = pendingTrades.stream().filter((e) ->
tradeManager.getCurrentPendingTrade() != null &&
e.getTrade().getId().equals(tradeManager.getCurrentPendingTrade().getId())).findFirst();
if (currentTradeItemOptional.isPresent())
selectPendingTrade(currentTradeItemOptional.get());
else if (pendingTrades.size() > 0)
selectPendingTrade(pendingTrades.get(0));
}
@SuppressWarnings("EmptyMethod")
@Override
public void deactivate() {
super.deactivate();
}
@SuppressWarnings("EmptyMethod")
@Override
public void terminate() {
super.terminate();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Methods
///////////////////////////////////////////////////////////////////////////////////////////
public void selectPendingTrade(PendingTradesListItem item) {
if (item != null) {
currentItem = item;
isOfferer = tradeManager.isTradeMyOffer(currentItem.getTrade());
selectedIndex.set(pendingTrades.indexOf(item));
Trade currentTrade = currentItem.getTrade();
if (currentTrade.getDepositTx() != null) {
walletFacade.addTxConfidenceListener(new TxConfidenceListener(currentItem.getTrade()
.getDepositTx().getHashAsString()) {
@Override
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
updateConfidence(confidence);
}
});
updateConfidence(walletFacade.getConfidenceForTxId(currentItem.getTrade().getDepositTx()
.getHashAsString()));
}
currentTrade.stateProperty().addListener((ov, oldValue, newValue) -> tradeState.set(newValue));
tradeState.set(currentTrade.stateProperty().get());
currentTrade.faultProperty().addListener((ov, oldValue, newValue) -> fault.set(newValue));
fault.set(currentTrade.faultProperty().get());
}
}
public void paymentStarted() {
tradeManager.bankTransferInited(currentItem.getTrade().getId());
}
public void paymentReceived() {
tradeManager.onFiatReceived(currentItem.getTrade().getId());
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
ObservableList<PendingTradesListItem> getPendingTrades() {
return pendingTrades;
}
public boolean isOfferer() {
return isOfferer;
}
public Trade getTrade() {
return currentItem.getTrade();
}
public String getTxID() {
if (currentItem.getTrade().getDepositTx() != null)
return currentItem.getTrade().getDepositTx().getHashAsString();
else
return null;
}
public Coin getTotalFees() {
Coin tradeFee = isOfferer() ? FeePolicy.CREATE_OFFER_FEE : FeePolicy.TAKE_OFFER_FEE;
return tradeFee.add(FeePolicy.TX_FEE);
}
public WalletFacade getWalletFacade() {
return walletFacade;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private void updateConfidence(TransactionConfidence confidence) {
if (confidence != null && confidence.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
currentItem.getTrade().setState(Trade.State.DEPOSIT_CONFIRMED);
}
}

View file

@ -0,0 +1,250 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.orders.pending;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.PresentationModel;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.locale.BSResources;
import io.bitsquare.trade.Direction;
import io.bitsquare.trade.Trade;
import com.google.inject.Inject;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PendingTradesPM extends PresentationModel<PendingTradesModel> {
private static final Logger log = LoggerFactory.getLogger(PendingTradesPM.class);
private BSFormatter formatter;
private BSResources resources;
enum State {
TAKER_SELLER_WAIT_TX_CONF,
TAKER_SELLER_WAIT_PAYMENT_STARTED,
TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT,
TAKER_SELLER_COMPLETED,
OFFERER_BUYER_WAIT_TX_CONF,
OFFERER_BUYER_START_PAYMENT,
OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED,
OFFERER_BUYER_COMPLETED,
}
final StringProperty amount = new SimpleStringProperty();
final StringProperty price = new SimpleStringProperty();
final StringProperty volume = new SimpleStringProperty();
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
final ObjectProperty<State> state = new SimpleObjectProperty<>();
final ObjectProperty<Trade.State> tradeState = new SimpleObjectProperty<>();
final ObjectProperty<Throwable> fault = new SimpleObjectProperty<>();
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public PendingTradesPM(PendingTradesModel model, BSFormatter formatter, BSResources resources) {
super(model);
this.formatter = formatter;
this.resources = resources;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void initialize() {
selectedIndex.bind(model.selectedIndex);
tradeState.addListener((ov, oldValue, newValue) -> {
updateState();
});
fault.bind(model.fault);
super.initialize();
}
@Override
public void activate() {
super.activate();
updateState();
}
@SuppressWarnings("EmptyMethod")
@Override
public void deactivate() {
super.deactivate();
}
@SuppressWarnings("EmptyMethod")
@Override
public void terminate() {
super.terminate();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Methods
///////////////////////////////////////////////////////////////////////////////////////////
public void selectPendingTrade(PendingTradesListItem item) {
model.selectPendingTrade(item);
}
public void paymentStarted() {
model.paymentStarted();
}
public void paymentReceived() {
model.paymentReceived();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
ObservableList<PendingTradesListItem> getPendingTrades() {
return model.getPendingTrades();
}
public boolean isOfferer() {
return model.isOfferer();
}
public String getTxID() {
return model.getTxID();
}
public WalletFacade getWalletFacade() {
return model.getWalletFacade();
}
String getAmount(PendingTradesListItem item) {
return (item != null) ? BSFormatter.formatCoin(item.getOffer().getAmount()) +
" (" + BSFormatter.formatCoin(item.getOffer().getMinAmount()) + ")" : "";
}
String getPrice(PendingTradesListItem item) {
return (item != null) ? BSFormatter.formatFiat(item.getOffer().getPrice()) : "";
}
String getVolume(PendingTradesListItem item) {
return (item != null) ? BSFormatter.formatFiat(item.getOffer().getOfferVolume()) +
" (" + BSFormatter.formatFiat(item.getOffer().getMinOfferVolume()) + ")" : "";
}
String getBankAccountType(PendingTradesListItem item) {
return (item != null) ? BSResources.get(item.getOffer().getBankAccountType().toString()) : "";
}
String getDirectionLabel(PendingTradesListItem item) {
// mirror direction!
if (item != null) {
Direction direction = item.getOffer().getDirection() == Direction.BUY ? Direction.SELL : Direction.BUY;
return BSFormatter.formatDirection(direction, true);
}
else {
return "";
}
}
String getPaymentMethod() {
return BSResources.get(model.getTrade().getContract().getTakerBankAccount().getBankAccountType().toString());
}
String getHolderName() {
return model.getTrade().getContract().getTakerBankAccount().getAccountHolderName();
}
String getPrimaryId() {
return model.getTrade().getContract().getTakerBankAccount().getAccountPrimaryID();
}
String getSecondaryId() {
return model.getTrade().getContract().getTakerBankAccount().getAccountSecondaryID();
}
String getTradeVolume() {
return formatter.formatCoinWithCode(model.getTrade().getTradeAmount());
}
String getFiatVolume() {
return formatter.formatFiatWithCode(model.getTrade().getTradeVolume());
}
String getTotalFees() {
return formatter.formatCoinWithCode(model.getTotalFees());
}
String getCollateral() {
return formatter.formatCoinWithCode(model.getTrade().getCollateralAmount());
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private void updateState() {
log.debug("updateState " + model.tradeState.get());
if (model.tradeState.get() != null) {
switch (model.tradeState.get()) {
case DEPOSIT_PUBLISHED:
state.set(model.isOfferer() ? State.OFFERER_BUYER_WAIT_TX_CONF : State.TAKER_SELLER_WAIT_TX_CONF);
break;
case DEPOSIT_CONFIRMED:
state.set(model.isOfferer() ? State.OFFERER_BUYER_START_PAYMENT : State
.TAKER_SELLER_WAIT_PAYMENT_STARTED);
break;
case PAYMENT_STARTED:
state.set(model.isOfferer() ? State.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED : State
.TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT);
break;
case PAYMENT_RECEIVED:
case PAYOUT_PUBLISHED:
state.set(model.isOfferer() ? State.OFFERER_BUYER_COMPLETED : State.TAKER_SELLER_COMPLETED);
break;
case FAULT:
// TODO
break;
default:
log.warn("unhandled state " + state);
break;
}
}
}
}

View file

@ -0,0 +1,187 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ This file is part of Bitsquare.
~
~ Bitsquare is free software: you can redistribute it and/or modify it
~ under the terms of the GNU Affero General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or (at
~ your option) any later version.
~
~ Bitsquare is distributed in the hope that it will be useful, but WITHOUT
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
~ License for more details.
~
~ You should have received a copy of the GNU Affero General Public License
~ along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
-->
<?import io.bitsquare.gui.components.InfoDisplay?>
<?import io.bitsquare.gui.components.processbar.ProcessStepBar?>
<?import io.bitsquare.gui.components.TextFieldWithCopyIcon?>
<?import io.bitsquare.gui.components.TitledGroupBg?>
<?import io.bitsquare.gui.components.TitledSeparator?>
<?import io.bitsquare.gui.components.TxIdTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane fx:id="root" fx:controller="io.bitsquare.gui.main.orders.pending.PendingTradesViewCB"
hgap="5.0" vgap="5"
xmlns:fx="http://javafx.com/fxml">
<padding>
<Insets bottom="20.0" left="25.0" top="30.0" right="25"/>
</padding>
<TitledSeparator text="Pending trades" GridPane.rowIndex="0" GridPane.columnIndex="0" GridPane.columnSpan="2"/>
<TableView fx:id="table" GridPane.rowIndex="0" GridPane.columnIndex="0" GridPane.columnSpan="2"
minHeight="120" prefHeight="120">
<GridPane.margin>
<Insets top="10.0" left="-10" right="-10" bottom="-15"/>
</GridPane.margin>
<columns>
<TableColumn text="Amount in BTC (Min.)" fx:id="amountColumn" minWidth="130"/>
<TableColumn text="Price" fx:id="priceColumn" minWidth="130"/>
<TableColumn text="Amount in EUR (Min.)" fx:id="volumeColumn" minWidth="130"/>
<TableColumn text="Country" fx:id="countryColumn" minWidth="60"/>
<TableColumn text="Bank transfer type" fx:id="bankAccountTypeColumn" minWidth="130"/>
<TableColumn text="Trade tye" fx:id="directionColumn" minWidth="80" sortable="false"/>
<TableColumn fx:id="selectColumn" minWidth="60" sortable="false" text=""/>
</columns>
</TableView>
<TitledGroupBg fx:id="titledGroupBg" text="Trade status" GridPane.rowIndex="1" GridPane.rowSpan="4"
GridPane.columnSpan="2" visible="false">
<GridPane.margin>
<Insets top="40.0" bottom="-10" left="-10" right="-10"/>
</GridPane.margin>
</TitledGroupBg>
<ProcessStepBar fx:id="processBar" GridPane.rowIndex="1" GridPane.columnSpan="2" snapToPixel="true" visible="false">
<GridPane.margin>
<Insets top="60.0"/>
</GridPane.margin>
</ProcessStepBar>
<Label fx:id="statusLabel" text="Status:" GridPane.rowIndex="2" visible="false">
<GridPane.margin>
<Insets top="20.0"/>
</GridPane.margin>
</Label>
<TextField fx:id="statusTextField" GridPane.rowIndex="2" GridPane.columnIndex="1" editable="false" visible="false">
<GridPane.margin>
<Insets top="20.0"/>
</GridPane.margin>
</TextField>
<Label fx:id="txIdLabel" text="Deposit transaction ID:" GridPane.rowIndex="3" visible="false"/>
<TxIdTextField fx:id="txIdTextField" GridPane.rowIndex="3" GridPane.columnIndex="1" visible="false"/>
<InfoDisplay fx:id="infoDisplay" onAction="#onOpenHelp" rowIndex="4" gridPane="$root" visible="false"/>
<Button fx:id="confirmPaymentReceiptButton" text="Confirm payment receipt" onAction="#onConfirmPaymentReceipt"
GridPane.rowIndex="5" GridPane.columnIndex="1" defaultButton="true" visible="false">
<GridPane.margin>
<Insets top="-5"/>
</GridPane.margin>
</Button>
<!--
Payments
-->
<TitledGroupBg fx:id="paymentsGroupBg" text="Payments details" GridPane.rowIndex="5" GridPane.rowSpan="5"
GridPane.columnSpan="2" visible="false">
<GridPane.margin>
<Insets top="40.0" bottom="-10" left="-10" right="-10"/>
</GridPane.margin>
</TitledGroupBg>
<Label fx:id="paymentMethodLabel" text="Payments method:" GridPane.rowIndex="5" visible="false">
<GridPane.margin>
<Insets top="60.0"/>
</GridPane.margin>
</Label>
<TextField fx:id="paymentMethodTextField" GridPane.rowIndex="5" GridPane.columnIndex="1" editable="false"
visible="false">
<GridPane.margin>
<Insets top="60.0"/>
</GridPane.margin>
</TextField>
<Label fx:id="holderNameLabel" text="Holder name:" GridPane.rowIndex="6" visible="false"/>
<TextFieldWithCopyIcon fx:id="holderNameTextField" GridPane.rowIndex="6" GridPane.columnIndex="1" visible="false"/>
<Label fx:id="primaryIdLabel" text="Primary ID:" GridPane.rowIndex="7" visible="false"/>
<TextFieldWithCopyIcon fx:id="primaryIdTextField" GridPane.rowIndex="7" GridPane.columnIndex="1" visible="false"/>
<Label fx:id="secondaryIdLabel" text="Secondary ID:" GridPane.rowIndex="8" visible="false"/>
<TextFieldWithCopyIcon fx:id="secondaryIdTextField" GridPane.rowIndex="8" GridPane.columnIndex="1" visible="false"/>
<InfoDisplay fx:id="paymentsInfoDisplay" onAction="#onOpenPaymentsHelp" rowIndex="9" gridPane="$root"
visible="false"/>
<Button fx:id="paymentsButton" text="Payment started" onAction="#onPaymentStarted" GridPane.rowIndex="10"
GridPane.columnIndex="1" defaultButton="true" visible="false">
<GridPane.margin>
<Insets top="15"/>
</GridPane.margin>
</Button>
<!--
Summary
-->
<TitledGroupBg fx:id="summaryGroupBg" text="Summary" GridPane.rowIndex="5" GridPane.rowSpan="5"
GridPane.columnSpan="2" visible="false">
<GridPane.margin>
<Insets top="40.0" bottom="-10" left="-10" right="-10"/>
</GridPane.margin>
</TitledGroupBg>
<Label fx:id="btcLabel" text="You have bought:" GridPane.rowIndex="5" visible="false">
<GridPane.margin>
<Insets top="60.0"/>
</GridPane.margin>
</Label>
<TextField fx:id="btcTextField" GridPane.rowIndex="5" GridPane.columnIndex="1" editable="false"
visible="false">
<GridPane.margin>
<Insets top="60.0"/>
</GridPane.margin>
</TextField>
<Label fx:id="fiatLabel" text="You have paid:" GridPane.rowIndex="6" visible="false"/>
<TextField fx:id="fiatTextField" GridPane.rowIndex="6" GridPane.columnIndex="1" editable="false" visible="false"/>
<Label fx:id="feesLabel" text="Total fees paid:" GridPane.rowIndex="7" visible="false"/>
<TextField fx:id="feesTextField" GridPane.rowIndex="7" GridPane.columnIndex="1" editable="false" visible="false"/>
<Label fx:id="collateralLabel" text="Refunded collateral:" GridPane.rowIndex="8" visible="false"/>
<TextField fx:id="collateralTextField" GridPane.rowIndex="8" GridPane.columnIndex="1" editable="false"
visible="false"/>
<InfoDisplay fx:id="summaryInfoDisplay" onAction="#onOpenSummaryHelp" rowIndex="9" gridPane="$root"
visible="false"/>
<columnConstraints>
<ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" minWidth="200"/>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
<rowConstraints>
<RowConstraints/>
<RowConstraints/>
<RowConstraints/>
<RowConstraints/>
<RowConstraints/>
<RowConstraints/>
<RowConstraints/>
<RowConstraints/>
<RowConstraints/>
<RowConstraints/>
<RowConstraints/>
</rowConstraints>
</GridPane>

View file

@ -0,0 +1,576 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.orders.pending;
import io.bitsquare.gui.CachedViewCB;
import io.bitsquare.gui.components.InfoDisplay;
import io.bitsquare.gui.components.TextFieldWithCopyIcon;
import io.bitsquare.gui.components.TitledGroupBg;
import io.bitsquare.gui.components.TxIdTextField;
import io.bitsquare.gui.components.processbar.ProcessStepBar;
import io.bitsquare.gui.components.processbar.ProcessStepItem;
import io.bitsquare.gui.main.help.Help;
import io.bitsquare.gui.main.help.HelpId;
import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.locale.Country;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javax.inject.Inject;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.util.Callback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
private static final Logger log = LoggerFactory.getLogger(PendingTradesViewCB.class);
public TitledGroupBg summaryGroupBg;
public Label btcLabel;
public TextField btcTextField;
public Label fiatLabel;
public TextField fiatTextField;
public Label feesLabel;
public TextField feesTextField;
public Label collateralLabel;
public TextField collateralTextField;
public InfoDisplay summaryInfoDisplay;
@FXML TitledGroupBg titledGroupBg, paymentsGroupBg;
@FXML ProcessStepBar processBar;
@FXML Label statusLabel, txIdLabel, paymentMethodLabel, holderNameLabel, primaryIdLabel, secondaryIdLabel;
@FXML TextField statusTextField, paymentMethodTextField;
@FXML TxIdTextField txIdTextField;
@FXML InfoDisplay infoDisplay, paymentsInfoDisplay;
@FXML Button confirmPaymentReceiptButton, paymentsButton;
@FXML TextFieldWithCopyIcon holderNameTextField, secondaryIdTextField, primaryIdTextField;
@FXML TableView<PendingTradesListItem> table;
@FXML TableColumn<PendingTradesListItem, PendingTradesListItem> priceColumn, amountColumn, volumeColumn,
directionColumn, countryColumn, bankAccountTypeColumn, selectColumn;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public PendingTradesViewCB(PendingTradesPM presentationModel) {
super(presentationModel);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void initialize(URL url, ResourceBundle rb) {
setAmountColumnCellFactory();
setPriceColumnCellFactory();
setVolumeColumnCellFactory();
setCountryColumnCellFactory();
setBankAccountTypeColumnCellFactory();
setDirectionColumnCellFactory();
setSelectColumnCellFactory();
table.setItems(presentationModel.getPendingTrades());
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.getSelectionModel().selectedItemProperty().
addListener((obsValue, oldValue, newValue) -> {
if (oldValue != newValue) {
if (oldValue != null && newValue != null)
presentationModel.selectPendingTrade(newValue);
else if (newValue == null)
table.getSelectionModel().clearSelection();
}
else {
log.error("####### should not happen!");
}
});
// need runLater to avoid conflict with user initiated selection
presentationModel.selectedIndex.addListener((ov, oldValue, newValue) ->
Platform.runLater(() -> table.getSelectionModel().select((int) newValue)));
super.initialize(url, rb);
}
@Override
public void activate() {
super.activate();
if (!presentationModel.getPendingTrades().isEmpty()) {
if (presentationModel.isOfferer())
setupScreenForOfferer();
else
setupScreenForTaker();
}
}
@SuppressWarnings("EmptyMethod")
@Override
public void deactivate() {
super.deactivate();
}
@SuppressWarnings("EmptyMethod")
@Override
public void terminate() {
super.terminate();
}
///////////////////////////////////////////////////////////////////////////////////////////
// GUI handlers
///////////////////////////////////////////////////////////////////////////////////////////
@FXML
void onPaymentStarted() {
presentationModel.paymentStarted();
}
@FXML
void onConfirmPaymentReceipt() {
presentationModel.paymentReceived();
}
@FXML
void onOpenHelp() {
Help.openWindow(presentationModel.isOfferer() ? HelpId.PENDING_TRADE_OFFERER : HelpId.PENDING_TRADE_TAKER);
}
@FXML
void onOpenPaymentsHelp() {
Help.openWindow(HelpId.PENDING_TRADE_PAYMENT);
}
@FXML
void onOpenSummaryHelp() {
Help.openWindow(HelpId.PENDING_TRADE_SUMMARY);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////////////////////////////////
private void setupScreenForOfferer() {
log.debug("setupScreenForOfferer");
titledGroupBg.setVisible(true);
processBar.setVisible(true);
statusLabel.setVisible(true);
statusTextField.setVisible(true);
txIdLabel.setVisible(true);
txIdTextField.setVisible(true);
infoDisplay.setVisible(true);
log.debug("setupScreenForTaker");
if (processBar.getProcessStepItems() == null) {
List<ProcessStepItem> items = new ArrayList<>();
items.add(new ProcessStepItem("Wait for block chain confirmation"));
items.add(new ProcessStepItem("Start payment"));
items.add(new ProcessStepItem("Wait for payment confirmation"));
items.add(new ProcessStepItem("Trade successful completed"));
processBar.setProcessStepItems(items);
}
txIdTextField.setup(presentationModel.getWalletFacade(), presentationModel.getTxID());
presentationModel.state.addListener((ov, oldValue, newValue) -> applyOffererState(newValue));
applyOffererState(presentationModel.state.get());
}
private void applyOffererState(PendingTradesPM.State state) {
if (state != null) {
paymentsGroupBg.setVisible(false);
paymentMethodLabel.setVisible(false);
holderNameLabel.setVisible(false);
primaryIdLabel.setVisible(false);
secondaryIdLabel.setVisible(false);
paymentMethodTextField.setVisible(false);
paymentsInfoDisplay.setVisible(false);
paymentsButton.setVisible(false);
holderNameTextField.setVisible(false);
primaryIdTextField.setVisible(false);
secondaryIdTextField.setVisible(false);
summaryGroupBg.setVisible(false);
btcLabel.setVisible(false);
btcTextField.setVisible(false);
fiatLabel.setVisible(false);
fiatTextField.setVisible(false);
feesLabel.setVisible(false);
feesTextField.setVisible(false);
collateralLabel.setVisible(false);
collateralTextField.setVisible(false);
summaryInfoDisplay.setVisible(false);
switch (state) {
case OFFERER_BUYER_WAIT_TX_CONF:
processBar.setSelectedIndex(0);
statusTextField.setText("Deposit transaction is published. Waiting " +
"for at least 1 confirmation");
infoDisplay.setText("Deposit transaction has bee published. You need to wait for at least one " +
"block " +
"chain confirmation. After that you need to make the payments transfer.");
break;
case OFFERER_BUYER_START_PAYMENT:
processBar.setSelectedIndex(1);
statusTextField.setText("Deposit transaction has at least 1 confirmation. Start payment.");
infoDisplay.setText("Deposit transaction has at least one blockchain confirmation. You need to " +
"start " +
"the payment.");
paymentsGroupBg.setVisible(true);
paymentMethodLabel.setVisible(true);
holderNameLabel.setVisible(true);
primaryIdLabel.setVisible(true);
secondaryIdLabel.setVisible(true);
paymentMethodTextField.setVisible(true);
paymentsInfoDisplay.setVisible(true);
holderNameTextField.setVisible(true);
primaryIdTextField.setVisible(true);
secondaryIdTextField.setVisible(true);
paymentsButton.setVisible(true);
paymentMethodTextField.setText(presentationModel.getPaymentMethod());
holderNameTextField.setText(presentationModel.getHolderName());
primaryIdTextField.setText(presentationModel.getPrimaryId());
secondaryIdTextField.setText(presentationModel.getSecondaryId());
paymentsInfoDisplay.setText("Copy and paste the payments accounts data to your payments " +
"accounts web page and transfer the payment to the other trader. When the transfer is " +
"done confirm it with the 'Payment started' button.");
break;
case OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED:
processBar.setSelectedIndex(2);
statusTextField.setText("Waiting until the other trader has received your payment.");
infoDisplay.setText("Waiting until the other trader has confirmed that he has received your " +
"payment.");
break;
case OFFERER_BUYER_COMPLETED:
processBar.setSelectedIndex(3);
statusTextField.setText("Trade has successfully completed.");
infoDisplay.setText("Trade has successfully completed. You can find the details to that trade" +
" in the closed trades section.");
summaryGroupBg.setVisible(true);
btcLabel.setVisible(true);
btcTextField.setVisible(true);
fiatLabel.setVisible(true);
fiatTextField.setVisible(true);
feesLabel.setVisible(true);
feesTextField.setVisible(true);
collateralLabel.setVisible(true);
collateralTextField.setVisible(true);
summaryInfoDisplay.setVisible(true);
btcTextField.setText(presentationModel.getTradeVolume());
fiatTextField.setText(presentationModel.getFiatVolume());
feesTextField.setText(presentationModel.getTotalFees());
collateralTextField.setText(presentationModel.getCollateral());
summaryInfoDisplay.setText("You can open that summary any time in the closed orders section.");
break;
}
}
}
private void setupScreenForTaker() {
titledGroupBg.setVisible(true);
processBar.setVisible(true);
statusLabel.setVisible(true);
statusTextField.setVisible(true);
txIdLabel.setVisible(true);
txIdTextField.setVisible(true);
infoDisplay.setVisible(true);
summaryGroupBg.setVisible(false);
btcLabel.setVisible(false);
btcTextField.setVisible(false);
fiatLabel.setVisible(false);
fiatTextField.setVisible(false);
feesLabel.setVisible(false);
feesTextField.setVisible(false);
collateralLabel.setVisible(false);
collateralTextField.setVisible(false);
summaryInfoDisplay.setVisible(false);
log.debug("setupScreenForTaker");
if (processBar.getProcessStepItems() == null) {
List<ProcessStepItem> items = new ArrayList<>();
items.add(new ProcessStepItem("Wait for block chain confirmation"));
items.add(new ProcessStepItem("Wait for payment started"));
items.add(new ProcessStepItem("Confirm payment"));
items.add(new ProcessStepItem("Trade successful completed"));
processBar.setProcessStepItems(items);
}
txIdTextField.setup(presentationModel.getWalletFacade(), presentationModel.getTxID());
presentationModel.state.addListener((ov, oldValue, newValue) -> applyTakerState(newValue));
applyTakerState(presentationModel.state.get());
}
private void applyTakerState(PendingTradesPM.State state) {
log.debug("#### state " + state);
if (state != null) {
confirmPaymentReceiptButton.setVisible(false);
switch (state) {
case TAKER_SELLER_WAIT_TX_CONF:
processBar.setSelectedIndex(0);
statusTextField.setText("Deposit transaction is published. Waiting for at least 1 confirmation");
infoDisplay.setText("Deposit transaction has bee published. He needs to wait for at least one " +
"blockchain " +
"confirmation.");
break;
case TAKER_SELLER_WAIT_PAYMENT_STARTED:
processBar.setSelectedIndex(1);
statusTextField.setText("Deposit transaction has at least 1 confirmation. Waiting that other " +
"trader starts payment.");
infoDisplay.setText("Deposit transaction has at least one blockchain " +
"confirmation. The other trader need to start the payment. You will get informed when " +
"that been done.");
break;
case TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT:
processBar.setSelectedIndex(2);
statusTextField.setText("Payment is on the way. Check your payments account and confirm when you " +
"have received the payment.");
infoDisplay.setText("The other trader has started the payment. You need to check your payments " +
"account and confirm the payment when the money has arrived there.");
confirmPaymentReceiptButton.setVisible(true);
break;
case TAKER_SELLER_COMPLETED:
processBar.setSelectedIndex(3);
statusTextField.setText("Trade has successfully completed.");
infoDisplay.setText("Trade has successfully completed. You can find the details to that trade" +
" in the closed trades section.");
summaryGroupBg.setVisible(true);
btcLabel.setVisible(true);
btcTextField.setVisible(true);
fiatLabel.setVisible(true);
fiatTextField.setVisible(true);
feesLabel.setVisible(true);
feesTextField.setVisible(true);
collateralLabel.setVisible(true);
collateralTextField.setVisible(true);
summaryInfoDisplay.setVisible(true);
btcTextField.setText(presentationModel.getTradeVolume());
fiatTextField.setText(presentationModel.getFiatVolume());
feesTextField.setText(presentationModel.getTotalFees());
collateralTextField.setText(presentationModel.getCollateral());
summaryInfoDisplay.setText("You can open that summary any time in the closed orders section.");
break;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// CellFactories
///////////////////////////////////////////////////////////////////////////////////////////
private void setAmountColumnCellFactory() {
amountColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
amountColumn.setCellFactory(
new Callback<TableColumn<PendingTradesListItem, PendingTradesListItem>, TableCell<PendingTradesListItem,
PendingTradesListItem>>() {
@Override
public TableCell<PendingTradesListItem, PendingTradesListItem> call(
TableColumn<PendingTradesListItem, PendingTradesListItem> column) {
return new TableCell<PendingTradesListItem, PendingTradesListItem>() {
@Override
public void updateItem(final PendingTradesListItem item, boolean empty) {
super.updateItem(item, empty);
setText(presentationModel.getAmount(item));
}
};
}
});
}
private void setPriceColumnCellFactory() {
priceColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
priceColumn.setCellFactory(
new Callback<TableColumn<PendingTradesListItem, PendingTradesListItem>, TableCell<PendingTradesListItem,
PendingTradesListItem>>() {
@Override
public TableCell<PendingTradesListItem, PendingTradesListItem> call(
TableColumn<PendingTradesListItem, PendingTradesListItem> column) {
return new TableCell<PendingTradesListItem, PendingTradesListItem>() {
@Override
public void updateItem(final PendingTradesListItem item, boolean empty) {
super.updateItem(item, empty);
setText(presentationModel.getPrice(item));
}
};
}
});
}
private void setVolumeColumnCellFactory() {
volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
volumeColumn.setCellFactory(
new Callback<TableColumn<PendingTradesListItem, PendingTradesListItem>, TableCell<PendingTradesListItem,
PendingTradesListItem>>() {
@Override
public TableCell<PendingTradesListItem, PendingTradesListItem> call(
TableColumn<PendingTradesListItem, PendingTradesListItem> column) {
return new TableCell<PendingTradesListItem, PendingTradesListItem>() {
@Override
public void updateItem(final PendingTradesListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null)
setText(presentationModel.getVolume(item));
else
setText("");
}
};
}
});
}
private void setDirectionColumnCellFactory() {
directionColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
directionColumn.setCellFactory(
new Callback<TableColumn<PendingTradesListItem, PendingTradesListItem>, TableCell<PendingTradesListItem,
PendingTradesListItem>>() {
@Override
public TableCell<PendingTradesListItem, PendingTradesListItem> call(
TableColumn<PendingTradesListItem, PendingTradesListItem> column) {
return new TableCell<PendingTradesListItem, PendingTradesListItem>() {
@Override
public void updateItem(final PendingTradesListItem item, boolean empty) {
super.updateItem(item, empty);
setText(presentationModel.getDirectionLabel(item));
}
};
}
});
}
private void setCountryColumnCellFactory() {
countryColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
countryColumn.setCellFactory(
new Callback<TableColumn<PendingTradesListItem, PendingTradesListItem>, TableCell<PendingTradesListItem,
PendingTradesListItem>>() {
@Override
public TableCell<PendingTradesListItem, PendingTradesListItem> call(
TableColumn<PendingTradesListItem, PendingTradesListItem> column) {
return new TableCell<PendingTradesListItem, PendingTradesListItem>() {
final HBox hBox = new HBox();
{
hBox.setSpacing(3);
hBox.setAlignment(Pos.CENTER);
setGraphic(hBox);
}
@Override
public void updateItem(final PendingTradesListItem item, boolean empty) {
super.updateItem(item, empty);
hBox.getChildren().clear();
if (item != null) {
Country country = item.getOffer().getBankAccountCountry();
hBox.getChildren().add(ImageUtil.getCountryIconImageView(item
.getOffer().getBankAccountCountry()));
Tooltip.install(this, new Tooltip(country.getName()));
}
}
};
}
});
}
private void setBankAccountTypeColumnCellFactory() {
bankAccountTypeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
bankAccountTypeColumn.setCellFactory(
new Callback<TableColumn<PendingTradesListItem, PendingTradesListItem>, TableCell<PendingTradesListItem,
PendingTradesListItem>>() {
@Override
public TableCell<PendingTradesListItem, PendingTradesListItem> call(
TableColumn<PendingTradesListItem, PendingTradesListItem> column) {
return new TableCell<PendingTradesListItem, PendingTradesListItem>() {
@Override
public void updateItem(final PendingTradesListItem item, boolean empty) {
super.updateItem(item, empty);
setText(presentationModel.getBankAccountType(item));
}
};
}
});
}
private void setSelectColumnCellFactory() {
selectColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue()));
selectColumn.setCellFactory(new Callback<TableColumn<PendingTradesListItem, PendingTradesListItem>,
TableCell<PendingTradesListItem, PendingTradesListItem>>() {
@Override
public TableCell<PendingTradesListItem, PendingTradesListItem> call(
TableColumn<PendingTradesListItem, PendingTradesListItem> column) {
return new TableCell<PendingTradesListItem, PendingTradesListItem>() {
final Button button = new Button("Select");
@Override
public void updateItem(final PendingTradesListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
button.setOnAction(event -> showTradeDetails(item));
setGraphic(button);
}
else {
setGraphic(null);
}
}
};
}
private void showTradeDetails(PendingTradesListItem item) {
presentationModel.selectPendingTrade(item);
}
});
}
}

View file

@ -81,16 +81,15 @@ public class TradeViewCB extends CachedViewCB implements TradeNavigator {
@Override
public void initialize(URL url, ResourceBundle rb) {
direction = (this instanceof BuyViewCB) ? Direction.BUY : Direction.SELL;
navigationItem = (direction == Direction.BUY) ? Navigation.Item.BUY : Navigation.Item.SELL;
listener = navigationItems -> {
if (navigationItems != null && navigationItems.length == 3 && navigationItems[1] == navigationItem) {
loadView(navigationItems[2]);
}
};
direction = (this instanceof BuyViewCB) ? Direction.BUY : Direction.SELL;
// orderBookInfo.setDirection(direction);
navigationItem = (direction == Direction.BUY) ? Navigation.Item.BUY : Navigation.Item.SELL;
super.initialize(url, rb);
}
@ -126,6 +125,8 @@ public class TradeViewCB extends CachedViewCB implements TradeNavigator {
@Override
public void deactivate() {
super.deactivate();
navigation.removeListener(listener);
}
@SuppressWarnings("EmptyMethod")
@ -225,9 +226,6 @@ public class TradeViewCB extends CachedViewCB implements TradeNavigator {
log.error(e.getMessage());
}
}
else {
log.error("navigationItem not supported: " + navigationItem);
}
return null;
}

View file

@ -17,8 +17,8 @@
~ along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
-->
<?import io.bitsquare.gui.components.btc.AddressTextField?>
<?import io.bitsquare.gui.components.btc.BalanceTextField?>
<?import io.bitsquare.gui.components.AddressTextField?>
<?import io.bitsquare.gui.components.BalanceTextField?>
<?import io.bitsquare.gui.components.InfoDisplay?>
<?import io.bitsquare.gui.components.InputTextField?>
<?import io.bitsquare.gui.components.TitledGroupBg?>
@ -77,7 +77,7 @@
</VBox>
<Label text="x">
<font>
<Font name="Helvetica" size="20.0"/>
<Font name="Helvetica-Bold" size="20.0"/>
</font>
<padding>
<Insets top="14.0" left="3" right="3"/>
@ -96,7 +96,7 @@
<Label text="=">
<font>
<Font name="Helvetica" size="20.0"/>
<Font name="Helvetica-Bold" size="20.0"/>
</font>
<padding>
<Insets top="14.0" left="2" right="2"/>
@ -127,7 +127,7 @@
</HBox>
</VBox>
<InfoDisplay gridPane="$gridPane" onAction="#onOpenGeneralHelp" rowIndex="2"
<InfoDisplay gridPane="$gridPane" onAction="#onOpenGeneralHelp" rowIndex="2"
text="%createOffer.amountPriceBox.info"/>
<Button fx:id="showPaymentInfoScreenButton" text="%createOffer.amountPriceBox.next" id="show-details-button"
@ -245,7 +245,7 @@
</TextField>
<InfoDisplay fx:id="advancedInfoDisplay" gridPane="$gridPane" onAction="#onOpenAdvancedSettingsHelp"
rowIndex="15" visible="false"
rowIndex="15" visible="false"
text="%createOffer.advancedBox.info">
</InfoDisplay>

View file

@ -21,12 +21,12 @@ import io.bitsquare.gui.CachedViewCB;
import io.bitsquare.gui.CloseListener;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.OverlayManager;
import io.bitsquare.gui.components.AddressTextField;
import io.bitsquare.gui.components.BalanceTextField;
import io.bitsquare.gui.components.InfoDisplay;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.components.TitledGroupBg;
import io.bitsquare.gui.components.btc.AddressTextField;
import io.bitsquare.gui.components.btc.BalanceTextField;
import io.bitsquare.gui.main.help.Help;
import io.bitsquare.gui.main.help.HelpId;
import io.bitsquare.gui.util.ImageUtil;

View file

@ -31,7 +31,6 @@ import java.util.List;
import javax.inject.Inject;
import javafx.animation.AnimationTimer;
import javafx.beans.InvalidationListener;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
@ -58,7 +57,7 @@ public class OrderBook {
private final ObservableList<OrderBookListItem> orderBookListItems = FXCollections.observableArrayList();
private final OrderBookListener orderBookListener;
private final ChangeListener<BankAccount> bankAccountChangeListener;
private final InvalidationListener invalidationListener;
private final ChangeListener<Number> invalidationListener;
private String fiatCode;
private AnimationTimer pollingTimer;
private Country country;
@ -75,7 +74,10 @@ public class OrderBook {
this.user = user;
bankAccountChangeListener = (observableValue, oldValue, newValue) -> setBankAccount(newValue);
invalidationListener = (ov) -> requestOffers();
invalidationListener = (ov, oldValue, newValue) -> {
log.debug("#### invalidationListener " + newValue);
requestOffers();
};
orderBookListener = new OrderBookListener() {
@Override
@ -142,12 +144,14 @@ public class OrderBook {
}
private void addListeners() {
log.debug("addListeners ");
user.currentBankAccountProperty().addListener(bankAccountChangeListener);
messageFacade.addOrderBookListener(orderBookListener);
messageFacade.invalidationTimestampProperty().addListener(invalidationListener);
}
private void removeListeners() {
log.debug("removeListeners ");
user.currentBankAccountProperty().removeListener(bankAccountChangeListener);
messageFacade.removeOrderBookListener(orderBookListener);
messageFacade.invalidationTimestampProperty().removeListener(invalidationListener);
@ -160,6 +164,7 @@ public class OrderBook {
}
private void requestOffers() {
log.debug("#### requestOffers");
messageFacade.getOffers(fiatCode);
}
@ -173,7 +178,7 @@ public class OrderBook {
addListeners();
setBankAccount(user.getCurrentBankAccount());
pollingTimer = Utilities.setInterval(1000, (animationTimer) -> {
messageFacade.requestInvalidationTimeStamp(fiatCode);
messageFacade.requestInvalidationTimeStampFromDHT(fiatCode);
return null;
});

View file

@ -52,7 +52,7 @@
</VBox>
<Label text="x">
<font>
<Font name="Helvetica" size="20.0"/>
<Font name="Helvetica-Bold" size="20.0"/>
</font>
<padding>
<Insets top="14.0" left="3" right="3"/>
@ -71,7 +71,7 @@
<Label text="=">
<font>
<Font name="Helvetica" size="20.0"/>
<Font name="Helvetica-Bold" size="20.0"/>
</font>
<padding>
<Insets top="14.0" left="2" right="2"/>

View file

@ -351,7 +351,7 @@ public class OrderBookViewCB extends CachedViewCB<OrderBookPM> {
OrderBookListItem>>() {
@Override
public TableCell<OrderBookListItem, OrderBookListItem> call(
TableColumn<OrderBookListItem, OrderBookListItem> directionColumn) {
TableColumn<OrderBookListItem, OrderBookListItem> column) {
return new TableCell<OrderBookListItem, OrderBookListItem>() {
@Override
public void updateItem(final OrderBookListItem item, boolean empty) {
@ -370,7 +370,7 @@ public class OrderBookViewCB extends CachedViewCB<OrderBookPM> {
OrderBookListItem>>() {
@Override
public TableCell<OrderBookListItem, OrderBookListItem> call(
TableColumn<OrderBookListItem, OrderBookListItem> directionColumn) {
TableColumn<OrderBookListItem, OrderBookListItem> column) {
return new TableCell<OrderBookListItem, OrderBookListItem>() {
@Override
public void updateItem(final OrderBookListItem item, boolean empty) {
@ -389,7 +389,7 @@ public class OrderBookViewCB extends CachedViewCB<OrderBookPM> {
OrderBookListItem>>() {
@Override
public TableCell<OrderBookListItem, OrderBookListItem> call(
TableColumn<OrderBookListItem, OrderBookListItem> directionColumn) {
TableColumn<OrderBookListItem, OrderBookListItem> column) {
return new TableCell<OrderBookListItem, OrderBookListItem>() {
@Override
public void updateItem(final OrderBookListItem item, boolean empty) {
@ -409,7 +409,7 @@ public class OrderBookViewCB extends CachedViewCB<OrderBookPM> {
@Override
public TableCell<OrderBookListItem, OrderBookListItem> call(
TableColumn<OrderBookListItem, OrderBookListItem> directionColumn) {
TableColumn<OrderBookListItem, OrderBookListItem> column) {
return new TableCell<OrderBookListItem, OrderBookListItem>() {
final ImageView iconView = new ImageView();
final Button button = new Button();
@ -493,7 +493,7 @@ public class OrderBookViewCB extends CachedViewCB<OrderBookPM> {
@Override
public TableCell<OrderBookListItem, OrderBookListItem> call(
TableColumn<OrderBookListItem, OrderBookListItem> directionColumn) {
TableColumn<OrderBookListItem, OrderBookListItem> column) {
return new TableCell<OrderBookListItem, OrderBookListItem>() {
final HBox hBox = new HBox();
@ -527,7 +527,7 @@ public class OrderBookViewCB extends CachedViewCB<OrderBookPM> {
OrderBookListItem>>() {
@Override
public TableCell<OrderBookListItem, OrderBookListItem> call(
TableColumn<OrderBookListItem, OrderBookListItem> directionColumn) {
TableColumn<OrderBookListItem, OrderBookListItem> column) {
return new TableCell<OrderBookListItem, OrderBookListItem>() {
@Override
public void updateItem(final OrderBookListItem orderBookListItem, boolean empty) {

View file

@ -26,8 +26,6 @@ import io.bitsquare.settings.Settings;
import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferProtocol;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferProtocolListener;
import com.google.bitcoin.core.Coin;
import com.google.bitcoin.utils.ExchangeRate;
@ -155,116 +153,24 @@ class TakeOfferModel extends UIModel {
}
void takeOffer() {
// data validation is done in the trade domain
/*tradeManager.requestPlaceOffer(orderBookInfo.getOffer().getId(),
orderBookInfo.getOffer().getDirection(),
priceAsFiat.get(),
amountAsCoin.get(),
minAmountAsCoin.get(),
(transaction) -> {
transactionId.set(transaction.getHashAsString());
Trade trade = tradeManager.takeOffer(amountAsCoin.get(), offer);
trade.stateProperty().addListener((ov, oldValue, newValue) -> {
switch (newValue) {
case DEPOSIT_PUBLISHED:
transactionId.set(trade.getDepositTx().getHashAsString());
requestTakeOfferSuccess.set(true);
},
requestTakeOfferErrorMessage::set
);*/
SellerTakesOfferProtocolListener listener = new SellerTakesOfferProtocolListener() {
@Override
public void onDepositTxPublished(String depositTxId) {
transactionId.set(depositTxId);
requestTakeOfferSuccess.set(true);
}
@Override
public void onBankTransferInited(String tradeId) {
break;
case FAULT:
requestTakeOfferErrorMessage.set("An error occurred. Error: " + trade.getFault().getMessage());
break;
case OFFERER_REJECTED:
requestTakeOfferErrorMessage.set("Take offer request got rejected.");
break;
}
@Override
public void onPayoutTxPublished(Trade trade, String hashAsString) {
}
@Override
public void onFault(Throwable throwable, SellerTakesOfferProtocol.State state) {
requestTakeOfferErrorMessage.set("An error occurred. Error: " + throwable.getMessage());
}
@Override
public void onWaitingForPeerResponse(SellerTakesOfferProtocol.State state) {
}
@Override
public void onCompleted(SellerTakesOfferProtocol.State state) {
}
@Override
public void onTakeOfferRequestRejected(Trade trade) {
requestTakeOfferErrorMessage.set("Take offer request got rejected.");
}
};
tradeManager.takeOffer(amountAsCoin.get(), offer, listener);
/*new SellerTakesOfferProtocolListener() {
@Override
public void onDepositTxPublished(String depositTxId) {
setDepositTxId(depositTxId);
accordion.setExpandedPane(waitBankTxTitledPane);
infoLabel.setText("Deposit transaction published by offerer.\n" +
"As soon as the offerer starts the \n" +
"Bank transfer, you will be informed.");
depositTxIdTextField.setText(depositTxId);
}
@Override
public void onBankTransferInited(String tradeId) {
setTradeId(tradeId);
headLineLabel.setText("Bank transfer initiated");
infoLabel.setText("Check your bank account and continue \n" + "when you have received the money.");
receivedFiatButton.setDisable(false);
}
@Override
public void onPayoutTxPublished(Trade trade, String payoutTxId) {
accordion.setExpandedPane(summaryTitledPane);
summaryPaidTextField.setText(BSFormatter.formatCoinWithCode(trade.getTradeAmount()));
summaryReceivedTextField.setText(BSFormatter.formatFiat(trade.getTradeVolume()));
summaryFeesTextField.setText(BSFormatter.formatCoinWithCode(
FeePolicy.TAKE_OFFER_FEE.add(FeePolicy.TX_FEE)));
summaryCollateralTextField.setText(BSFormatter.formatCoinWithCode(
trade.getCollateralAmount()));
summaryDepositTxIdTextField.setText(depositTxId);
summaryPayoutTxIdTextField.setText(payoutTxId);
}
@Override
public void onFault(Throwable throwable, SellerTakesOfferProtocol.State state) {
log.error("Error while executing trade process at state: " + state + " / " + throwable);
Popups.openErrorPopup("Error while executing trade process",
"Error while executing trade process at state: " + state + " / " + throwable);
}
@Override
public void onWaitingForPeerResponse(SellerTakesOfferProtocol.State state) {
log.debug("Waiting for peers response at state " + state);
}
@Override
public void onCompleted(SellerTakesOfferProtocol.State state) {
log.debug("Trade protocol completed at state " + state);
}
@Override
public void onTakeOfferRequestRejected(Trade trade) {
log.error("Take offer request rejected");
Popups.openErrorPopup("Take offer request rejected",
"Your take offer request has been rejected. It might be that the offerer got another " +
"request shortly before your request arrived.");
}
});*/
});
}
void calculateVolume() {

View file

@ -17,8 +17,8 @@
~ along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
-->
<?import io.bitsquare.gui.components.btc.AddressTextField?>
<?import io.bitsquare.gui.components.btc.BalanceTextField?>
<?import io.bitsquare.gui.components.AddressTextField?>
<?import io.bitsquare.gui.components.BalanceTextField?>
<?import io.bitsquare.gui.components.InfoDisplay?>
<?import io.bitsquare.gui.components.InputTextField?>
<?import io.bitsquare.gui.components.TitledGroupBg?>
@ -77,7 +77,7 @@
</VBox>
<Label text="x">
<font>
<Font name="Helvetica" size="20.0"/>
<Font name="Helvetica-Bold" size="20.0"/>
</font>
<padding>
<Insets top="14.0" left="3" right="3"/>
@ -92,7 +92,7 @@
<Label text="=">
<font>
<Font name="Helvetica" size="20.0"/>
<Font name="Helvetica-Bold" size="20.0"/>
</font>
<padding>
<Insets top="14.0" left="2" right="2"/>

View file

@ -22,12 +22,12 @@ import io.bitsquare.gui.CachedViewCB;
import io.bitsquare.gui.CloseListener;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.OverlayManager;
import io.bitsquare.gui.components.AddressTextField;
import io.bitsquare.gui.components.BalanceTextField;
import io.bitsquare.gui.components.InfoDisplay;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.components.TitledGroupBg;
import io.bitsquare.gui.components.btc.AddressTextField;
import io.bitsquare.gui.components.btc.BalanceTextField;
import io.bitsquare.gui.main.help.Help;
import io.bitsquare.gui.main.help.HelpId;
import io.bitsquare.gui.util.ImageUtil;
@ -318,6 +318,8 @@ public class TakeOfferViewCB extends CachedViewCB<TakeOfferPM> {
public void handle(ActionEvent actionEvent) {
try {
close();
navigation.navigationTo(Navigation.Item.MAIN, Navigation.Item.ORDERS,
Navigation.Item.PENDING_TRADES);
} catch (Exception e) {
e.printStackTrace();
}

View file

@ -20,8 +20,10 @@ package io.bitsquare.gui.util;
import javafx.scene.paint.*;
public class Colors {
public static final Paint BLUE = Color.valueOf("#0096c9");
public static final Paint LIGHT_GREY = Color.valueOf("#f4f4f4");
public static final Paint BLUE = Color.valueOf("#0f87c3");
public static final Paint LIGHT_GREY = Color.valueOf("#AAAAAA");
public static final Paint MID_GREY = Color.valueOf("#666666");
public static final Paint DARK_GREY = Color.valueOf("#333333");
public static final Paint GREEN = Color.valueOf("#00AA00");
}

View file

@ -22,6 +22,7 @@ import com.google.common.base.Stopwatch;
import java.util.concurrent.TimeUnit;
import javafx.animation.AnimationTimer;
import javafx.scene.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -59,11 +60,21 @@ public class Profiler {
counter++;
long elapsed = (System.currentTimeMillis() - lastFPSTime);
if (elapsed > 19)
log.trace("FPS: elapsed: {}ms / FPS total counter: {}", elapsed, counter);
log.trace("Profiler: last frame used {}ms", elapsed);
lastFPSTime = System.currentTimeMillis();
}
};
fpsTimer.start();
}
public static void initScene(Scene scene) {
/* PerformanceTracker tracker = PerformanceTracker.getSceneTracker(scene);
Timeline timeline = new Timeline(
new KeyFrame(Duration.seconds(1), t -> {
log.trace("FPS (tracker.getAverageFPS) = " + tracker.getAverageFPS());
}));
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();*/
}
}

View file

@ -191,7 +191,7 @@ public class MessageFacade implements MessageBroker {
});
// TODO will be removed when we don't use polling anymore
updateInvalidationTimestamp(locationKey);
writeInvalidationTimestampToDHT(locationKey);
log.trace("Add offer to DHT was successful. Added data: [locationKey: " + locationKey +
", value: " + offerData + "]");
});
@ -246,7 +246,7 @@ public class MessageFacade implements MessageBroker {
log.error("Remove offer from DHT failed. Error: " + e.getMessage());
}
});
updateInvalidationTimestamp(locationKey);
writeInvalidationTimestampToDHT(locationKey);
});
log.trace("Remove offer from DHT was successful. Removed data: [key: " + locationKey + ", " +
@ -448,7 +448,7 @@ public class MessageFacade implements MessageBroker {
// Polling
///////////////////////////////////////////////////////////////////////////////////////////
private void updateInvalidationTimestamp(Number160 locationKey) {
private void writeInvalidationTimestampToDHT(Number160 locationKey) {
invalidationTimestamp.set(System.currentTimeMillis());
try {
FuturePut putFuture = p2pNode.putData(getInvalidatedLocationKey(locationKey),
@ -477,7 +477,7 @@ public class MessageFacade implements MessageBroker {
return invalidationTimestamp;
}
public void requestInvalidationTimeStamp(String currencyCode) {
public void requestInvalidationTimeStampFromDHT(String currencyCode) {
Number160 locationKey = Number160.createHash(currencyCode);
try {
FutureGet getFuture = p2pNode.getData(getInvalidatedLocationKey(locationKey));
@ -490,8 +490,8 @@ public class MessageFacade implements MessageBroker {
final Object object = data.object();
Platform.runLater(() -> {
Long timeStamp = (Long) object;
// log.trace("Get invalidationTimestamp from DHT was successful. TimeStamp=" +
// timeStamp);
log.trace("Get invalidationTimestamp from DHT was successful. TimeStamp=" +
timeStamp);
invalidationTimestamp.set(timeStamp);
});
}
@ -499,6 +499,10 @@ public class MessageFacade implements MessageBroker {
log.error("Get invalidationTimestamp from DHT failed. Data = " + data);
}
}
else if (getFuture.data() == null) {
// OK as nothing is set at the moment
log.trace("Get invalidationTimestamp from DHT returns null. That is ok for the startup.");
}
else {
log.error("Get invalidationTimestamp from DHT failed with reason:" + getFuture.failedReason());
}

View file

@ -23,44 +23,62 @@ import com.google.bitcoin.utils.Fiat;
import java.io.Serializable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.SimpleObjectProperty;
//TODO flatten down?
public class Trade implements Serializable {
private static final long serialVersionUID = -8275323072940974077L;
///////////////////////////////////////////////////////////////////////////////////////////
// Enum
///////////////////////////////////////////////////////////////////////////////////////////
public static enum State {
OPEN,
OFFERER_ACCEPTED,
OFFERER_REJECTED, /* For taker only*/
DEPOSIT_PUBLISHED,
DEPOSIT_CONFIRMED,
PAYMENT_STARTED,
PAYMENT_RECEIVED, /* For taker only*/
PAYOUT_PUBLISHED,
FAULT
}
private final Offer offer;
private String takeOfferFeeTxID;
private Coin tradeAmount;
private Contract contract;
private String contractAsJson;
private String takerSignature;
private Transaction depositTransaction;
private Transaction payoutTransaction;
private State state = State.OPEN;
private Transaction depositTx;
private Transaction payoutTx;
private State state;
private Throwable fault;
// The Property fields are not serialized and therefore not initialized when read from disc.
// We need to access then with the getter to be sure it is not null.
// Don't access them directly, use the getter method
transient private SimpleBooleanProperty _depositTxChangedProperty;
transient private SimpleBooleanProperty _payoutTxChangedProperty;
transient private SimpleBooleanProperty _contractChangedProperty;
transient private SimpleStringProperty _stateChangedProperty;
// When serialized those transient properties are not instantiated, so we instantiate them in the getters at first
// access. Only use the accessor not the private field.
// TODO use ObjectPropertys instead of BooleanProperty
transient private BooleanProperty _payoutTxChanged;
transient private BooleanProperty _contractChanged;
transient private ObjectProperty<Transaction> _depositTx;
transient private ObjectProperty<State> _state;
transient private ObjectProperty<Throwable> _fault;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public Trade(Offer offer) {
this.offer = offer;
_depositTxChangedProperty = new SimpleBooleanProperty();
_payoutTxChangedProperty = new SimpleBooleanProperty();
_contractChangedProperty = new SimpleBooleanProperty();
_stateChangedProperty = new SimpleStringProperty();
state = State.OPEN;
}
public Fiat getTradeVolume() {
return offer.getVolumeByAmount(tradeAmount);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
@ -86,9 +104,65 @@ public class Trade implements Serializable {
return contract;
}
public void setContractAsJson(String contractAsJson) {
this.contractAsJson = contractAsJson;
}
public void setContract(Contract contract) {
this.contract = contract;
_contractChangedProperty.set(!_contractChangedProperty.get());
contractChangedProperty().set(!contractChangedProperty().get());
}
public void setDepositTx(Transaction tx) {
this.depositTx = tx;
depositTxProperty().set(tx);
}
public void setPayoutTx(Transaction tx) {
this.payoutTx = tx;
payoutTxChangedProperty().set(!payoutTxChangedProperty().get());
}
public void setState(State state) {
this.state = state;
stateProperty().set(state);
}
public void setFault(Throwable fault) {
this.fault = fault;
faultProperty().set(fault);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public Fiat getTradeVolume() {
return offer.getVolumeByAmount(tradeAmount);
}
public String getTakerSignature() {
return takerSignature;
}
public Transaction getDepositTx() {
return depositTx;
}
public Transaction getPayoutTx() {
return payoutTx;
}
public State getState() {
return state;
}
public Throwable getFault() {
return fault;
}
public Coin getCollateralAmount() {
return tradeAmount.multiply(offer.getCollateral()).divide(1000L);
}
public String getId() {
@ -107,99 +181,40 @@ public class Trade implements Serializable {
return contractAsJson;
}
// When serialized those transient properties are not instantiated, so we need to instantiate them at first access
public ObjectProperty<Transaction> depositTxProperty() {
if (_depositTx == null)
_depositTx = new SimpleObjectProperty<>(depositTx);
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public void setContractAsJson(String contractAsJson) {
this.contractAsJson = contractAsJson;
return _depositTx;
}
public String getTakerSignature() {
return takerSignature;
public BooleanProperty contractChangedProperty() {
if (_contractChanged == null)
_contractChanged = new SimpleBooleanProperty();
return _contractChanged;
}
public Transaction getDepositTransaction() {
return depositTransaction;
public BooleanProperty payoutTxChangedProperty() {
if (_payoutTxChanged == null)
_payoutTxChanged = new SimpleBooleanProperty();
return _payoutTxChanged;
}
public void setDepositTransaction(Transaction depositTransaction) {
this.depositTransaction = depositTransaction;
depositTxChangedProperty().set(!depositTxChangedProperty().get());
public ObjectProperty<State> stateProperty() {
if (_state == null)
_state = new SimpleObjectProperty<>(state);
return _state;
}
public Transaction getPayoutTransaction() {
return payoutTransaction;
}
public void setPayoutTransaction(Transaction payoutTransaction) {
this.payoutTransaction = payoutTransaction;
payoutTxChangedProperty().set(!payoutTxChangedProperty().get());
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
stateChangedProperty().set(state.toString());
}
// The Property fields are not serialized and therefore not initialized when read from disc.
// We need to access then with the getter to be sure it is not null.
public SimpleBooleanProperty depositTxChangedProperty() {
if (_depositTxChangedProperty == null) _depositTxChangedProperty = new SimpleBooleanProperty();
return _depositTxChangedProperty;
public ObjectProperty<Throwable> faultProperty() {
if (_fault == null)
_fault = new SimpleObjectProperty<>(fault);
return _fault;
}
public SimpleBooleanProperty contractChangedProperty() {
if (_contractChangedProperty == null) _contractChangedProperty = new SimpleBooleanProperty();
return _contractChangedProperty;
}
public SimpleBooleanProperty payoutTxChangedProperty() {
if (_payoutTxChangedProperty == null) _payoutTxChangedProperty = new SimpleBooleanProperty();
return _payoutTxChangedProperty;
}
public SimpleStringProperty stateChangedProperty() {
if (_stateChangedProperty == null) _stateChangedProperty = new SimpleStringProperty();
return _stateChangedProperty;
}
public Coin getCollateralAmount() {
return tradeAmount.multiply(offer.getCollateral()).divide(1000L);
}
@Override
public String toString() {
return "Trade{" +
"offer=" + offer +
", takeOfferFeeTxID='" + takeOfferFeeTxID + '\'' +
", tradeAmount=" + tradeAmount +
", contract=" + contract +
", contractAsJson='" + contractAsJson + '\'' +
", takerSignature='" + takerSignature + '\'' +
", depositTransaction=" + depositTransaction +
", state=" + state +
'}';
}
///////////////////////////////////////////////////////////////////////////////////////////
// toString
///////////////////////////////////////////////////////////////////////////////////////////
public static enum State {
OPEN,
ACCEPTED,
COMPLETED
}
}

View file

@ -44,8 +44,6 @@ import io.bitsquare.user.User;
import com.google.bitcoin.core.Coin;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.TransactionConfidence;
import com.google.bitcoin.core.Utils;
import com.google.bitcoin.utils.Fiat;
import java.io.IOException;
@ -57,8 +55,8 @@ import java.util.Map;
import javax.inject.Inject;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import net.tomp2p.peers.PeerAddress;
@ -89,13 +87,11 @@ public class TradeManager {
private final Map<String, BuyerAcceptsOfferProtocol> offererAsBuyerProtocolMap = new HashMap<>();
private final Map<String, CreateOfferCoordinator> createOfferCoordinatorMap = new HashMap<>();
private final StringProperty newTradeProperty = new SimpleStringProperty();
private final Map<String, Offer> offers;
private final Map<String, Trade> trades;
private final ObservableMap<String, Offer> offers = FXCollections.observableHashMap();
private final ObservableMap<String, Trade> trades = FXCollections.observableHashMap();
// TODO There might be multiple pending trades
private Trade pendingTrade;
private Trade currentPendingTrade;
///////////////////////////////////////////////////////////////////////////////////////////
@ -115,18 +111,12 @@ public class TradeManager {
Object offersObject = persistence.read(this, "offers");
if (offersObject instanceof HashMap) {
offers = (Map<String, Offer>) offersObject;
}
else {
offers = new HashMap<>();
offers.putAll((Map<String, Offer>) offersObject);
}
Object tradesObject = persistence.read(this, "trades");
if (tradesObject instanceof HashMap) {
trades = (Map<String, Trade>) tradesObject;
}
else {
trades = new HashMap<>();
trades.putAll((Map<String, Trade>) tradesObject);
}
messageFacade.addIncomingTradeMessageListener(this::onIncomingTradeMessage);
@ -200,7 +190,8 @@ public class TradeManager {
resultHandler.onResult(transactionId);
} catch (Exception e) {
//TODO retry policy
errorMessageHandler.onFault("Could not save offer. Reason: " + e.getCause().getMessage());
errorMessageHandler.onFault("Could not save offer. Reason: " +
(e.getCause() != null ? e.getCause().getMessage() : e.toString()));
createOfferCoordinatorMap.remove(offer.getId());
}
},
@ -231,18 +222,6 @@ public class TradeManager {
messageFacade.removeOffer(offer);
}
public Trade takeOffer(Coin amount, Offer offer, SellerTakesOfferProtocolListener listener) {
Trade trade = createTrade(offer);
trade.setTradeAmount(amount);
SellerTakesOfferProtocol sellerTakesOfferProtocol = new SellerTakesOfferProtocol(
trade, listener, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user);
takerAsSellerProtocolMap.put(trade.getId(), sellerTakesOfferProtocol);
sellerTakesOfferProtocol.start();
return trade;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Manage trades
@ -254,10 +233,7 @@ public class TradeManager {
Trade trade = new Trade(offer);
trades.put(offer.getId(), trade);
saveTrades();
// for updating UIs
this.newTradeProperty.set(trade.getId());
persistTrades();
return trade;
}
@ -267,10 +243,7 @@ public class TradeManager {
log.error("trades does not contain the trade with the ID " + trade.getId());
trades.remove(trade.getId());
saveTrades();
// for updating UIs
this.newTradeProperty.set(null);
persistTrades();
}
@ -284,7 +257,7 @@ public class TradeManager {
Offer offer = offers.get(offerId);
Trade trade = createTrade(offer);
pendingTrade = trade;
currentPendingTrade = trade;
BuyerAcceptsOfferProtocol buyerAcceptsOfferProtocol = new BuyerAcceptsOfferProtocol(trade,
sender,
@ -296,57 +269,54 @@ public class TradeManager {
new BuyerAcceptsOfferProtocolListener() {
@Override
public void onOfferAccepted(Offer offer) {
trade.setState(Trade.State.OFFERER_ACCEPTED);
persistTrades();
removeOffer(offer);
}
@Override
public void onDepositTxPublished(String depositTxID) {
log.trace("trading onDepositTxPublishedMessage " + depositTxID);
public void onDepositTxPublished(Transaction depositTx) {
trade.setDepositTx(depositTx);
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
persistTrades();
log.trace("trading onDepositTxPublishedMessage " + depositTx.getHashAsString());
}
@Override
public void onDepositTxConfirmedUpdate(TransactionConfidence confidence) {
log.trace("trading onDepositTxConfirmedUpdate");
public void onDepositTxConfirmedInBlockchain() {
log.trace("trading onDepositTxConfirmedInBlockchain");
trade.setState(Trade.State.DEPOSIT_CONFIRMED);
persistTrades();
}
@Override
public void onPayoutTxPublished(String payoutTxAsHex) {
Transaction payoutTx = new Transaction(walletFacade.getWallet().getParams(),
Utils.parseAsHexOrBase58(payoutTxAsHex));
trade.setPayoutTransaction(payoutTx);
trade.setState(Trade.State.COMPLETED);
public void onPayoutTxPublished(Transaction payoutTx) {
trade.setPayoutTx(payoutTx);
trade.setState(Trade.State.PAYOUT_PUBLISHED);
persistTrades();
log.debug("trading onPayoutTxPublishedMessage");
}
@Override
public void onFault(Throwable throwable, BuyerAcceptsOfferProtocol.State state) {
log.error("Error while executing trade process at state: " + state + " / " + throwable);
/* Popups.openErrorPopup("Error while executing trade process",
"Error while executing trade process at state: " + state + " / " +
throwable);*/
trade.setFault(throwable);
trade.setState(Trade.State.FAULT);
persistTrades();
}
// probably not needed
@Override
public void onWaitingForPeerResponse(BuyerAcceptsOfferProtocol.State state) {
log.debug("Waiting for peers response at state " + state);
}
@Override
public void onCompleted(BuyerAcceptsOfferProtocol.State state) {
log.debug("Trade protocol completed at state " + state);
}
// probably not needed
@Override
public void onWaitingForUserInteraction(BuyerAcceptsOfferProtocol.State state) {
log.debug("Waiting for UI activity at state " + state);
}
@Override
public void onDepositTxConfirmedInBlockchain() {
log.trace("trading onDepositTxConfirmedInBlockchain");
}
});
if (!offererAsBuyerProtocolMap.containsKey(trade.getId())) {
@ -365,18 +335,91 @@ public class TradeManager {
}
}
public void bankTransferInited(String tradeUID) {
offererAsBuyerProtocolMap.get(tradeUID).onUIEventBankTransferInited();
public Trade takeOffer(Coin amount, Offer offer) {
Trade trade = createTrade(offer);
trade.setTradeAmount(amount);
currentPendingTrade = trade;
SellerTakesOfferProtocolListener listener = new SellerTakesOfferProtocolListener() {
@Override
public void onTakeOfferRequestAccepted(Trade trade) {
trade.setState(Trade.State.OFFERER_ACCEPTED);
persistTrades();
}
@Override
public void onTakeOfferRequestRejected(Trade trade) {
trade.setState(Trade.State.OFFERER_REJECTED);
persistTrades();
}
@Override
public void onDepositTxPublished(Transaction depositTx) {
trade.setDepositTx(depositTx);
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
persistTrades();
}
@Override
public void onBankTransferInited(String tradeId) {
trade.setState(Trade.State.PAYMENT_STARTED);
persistTrades();
}
@Override
public void onPayoutTxPublished(Trade trade, Transaction payoutTx) {
trade.setState(Trade.State.PAYOUT_PUBLISHED);
trade.setPayoutTx(payoutTx);
persistTrades();
}
@Override
public void onFault(Throwable throwable, SellerTakesOfferProtocol.State state) {
log.error("onFault: " + throwable.getMessage() + " / " + state);
}
// probably not needed
@Override
public void onWaitingForPeerResponse(SellerTakesOfferProtocol.State state) {
}
@Override
public void onCompleted(SellerTakesOfferProtocol.State state) {
trade.setState(Trade.State.PAYMENT_RECEIVED);
persistTrades();
}
};
SellerTakesOfferProtocol sellerTakesOfferProtocol = new SellerTakesOfferProtocol(
trade, listener, messageFacade, walletFacade, blockChainFacade, cryptoFacade,
user);
takerAsSellerProtocolMap.put(trade.getId(), sellerTakesOfferProtocol);
sellerTakesOfferProtocol.start();
return trade;
}
public void onFiatReceived(String tradeUID) {
takerAsSellerProtocolMap.get(tradeUID).onUIEventFiatReceived();
//TODO we don't support interruptions yet.
// If the user has shut down the app we lose the offererAsBuyerProtocolMap
// Also we don't support yet offline messaging (mail box)
public void bankTransferInited(String tradeId) {
offererAsBuyerProtocolMap.get(tradeId).onUIEventBankTransferInited();
trades.get(tradeId).setState(Trade.State.PAYMENT_STARTED);
persistTrades();
}
public void onFiatReceived(String tradeId) {
takerAsSellerProtocolMap.get(tradeId).onUIEventFiatReceived();
trades.get(tradeId).setState(Trade.State.PAYMENT_RECEIVED);
persistTrades();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Process incoming tradeMessages
///////////////////////////////////////////////////////////////////////////////////////////
// Routes the incoming messages to the responsible protocol
private void onIncomingTradeMessage(TradeMessage tradeMessage, PeerAddress sender) {
// log.trace("processTradingMessage TradeId " + tradeMessage.getTradeId());
log.trace("processTradingMessage instance " + tradeMessage.getClass().getSimpleName());
@ -403,6 +446,7 @@ public class TradeManager {
(RequestOffererPublishDepositTxMessage) tradeMessage);
}
else if (tradeMessage instanceof DepositTxPublishedMessage) {
persistTrades();
takerAsSellerProtocolMap.get(tradeId).onDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage);
}
else if (tradeMessage instanceof BankTransferInitedMessage) {
@ -422,12 +466,15 @@ public class TradeManager {
return trades.containsKey(offer.getId());
}
public boolean isTradeMyOffer(Trade trade) {
return trade.getOffer().getMessagePublicKey().equals(user.getMessagePublicKey());
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public Map<String, Trade> getTrades() {
public ObservableMap<String, Trade> getTrades() {
return trades;
}
@ -439,12 +486,8 @@ public class TradeManager {
return offers.get(offerId);
}
public Trade getPendingTrade() {
return pendingTrade;
}
public final StringProperty getNewTradeProperty() {
return this.newTradeProperty;
public Trade getCurrentPendingTrade() {
return currentPendingTrade;
}
@ -453,11 +496,11 @@ public class TradeManager {
///////////////////////////////////////////////////////////////////////////////////////////
private void persistOffers() {
persistence.write(this, "offers", offers);
persistence.write(this, "offers", (Map<String, Offer>) new HashMap<>(offers));
}
private void saveTrades() {
persistence.write(this, "trades", trades);
private void persistTrades() {
persistence.write(this, "trades", (Map<String, Trade>) new HashMap<>(trades));
}
@Nullable

View file

@ -44,6 +44,7 @@ import io.bitsquare.user.User;
import com.google.bitcoin.core.Coin;
import com.google.bitcoin.core.ECKey;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils;
import java.security.PublicKey;
@ -169,7 +170,6 @@ public class BuyerAcceptsOfferProtocol {
state = State.Init;
}
public void start() {
log.debug("start called " + step++);
state = State.HandleTakeOfferRequest;
@ -180,7 +180,7 @@ public class BuyerAcceptsOfferProtocol {
public void onResultHandleTakeOfferRequest(boolean takeOfferRequestAccepted) {
log.debug("onResultHandleTakeOfferRequest called " + step++);
if (takeOfferRequestAccepted) {
trade.setState(Trade.State.ACCEPTED);
trade.setState(Trade.State.OFFERER_ACCEPTED);
messageFacade.removeOffer(offer);
listener.onOfferAccepted(offer);
listener.onWaitingForPeerResponse(state);
@ -335,8 +335,7 @@ public class BuyerAcceptsOfferProtocol {
public void onResultSignAndPublishDepositTx(Transaction depositTransaction) {
log.debug("onResultSignAndPublishDepositTx called " + step++);
trade.setDepositTransaction(depositTransaction);
listener.onDepositTxPublished(depositTransaction.getHashAsString());
listener.onDepositTxPublished(depositTransaction);
state = State.SendDepositTxIdToTaker;
SendDepositTxIdToTaker.run(this::onResultSendDepositTxIdToTaker, this::onFault, peerAddress, messageFacade,
@ -348,7 +347,7 @@ public class BuyerAcceptsOfferProtocol {
state = State.SetupListenerForBlockChainConfirmation;
SetupListenerForBlockChainConfirmation.run(this::onResultSetupListenerForBlockChainConfirmation,
this::onFault, trade.getDepositTransaction(), listener);
this::onFault, trade.getDepositTx(), listener);
}
public void onResultSetupListenerForBlockChainConfirmation() {
@ -375,7 +374,7 @@ public class BuyerAcceptsOfferProtocol {
state = State.onUIEventBankTransferInited;
// next task
String depositTransactionId = trade.getDepositTransaction().getHashAsString();
String depositTransactionId = trade.getDepositTx().getHashAsString();
Coin tradeAmount = trade.getTradeAmount();
Coin collateral = trade.getCollateralAmount();
state = State.SendSignedPayoutTx;
@ -414,9 +413,9 @@ public class BuyerAcceptsOfferProtocol {
state = State.onPayoutTxPublishedMessage;
// next task
listener.onPayoutTxPublished(payoutTxAsHex);
listener.onCompleted(state);
Transaction payoutTx = new Transaction(walletFacade.getWallet().getParams(),
Utils.parseAsHexOrBase58(payoutTxAsHex));
listener.onPayoutTxPublished(payoutTx);
}

View file

@ -19,24 +19,20 @@ package io.bitsquare.trade.protocol.trade.offerer;
import io.bitsquare.trade.Offer;
import com.google.bitcoin.core.TransactionConfidence;
import com.google.bitcoin.core.Transaction;
public interface BuyerAcceptsOfferProtocolListener {
void onOfferAccepted(Offer offer);
void onDepositTxPublished(String depositTxID);
void onDepositTxPublished(Transaction depositTx);
void onDepositTxConfirmedInBlockchain();
void onDepositTxConfirmedUpdate(TransactionConfidence confidence);
void onPayoutTxPublished(String payoutTxID);
void onPayoutTxPublished(Transaction payoutTx);
void onFault(Throwable throwable, BuyerAcceptsOfferProtocol.State state);
void onWaitingForPeerResponse(BuyerAcceptsOfferProtocol.State state);
void onCompleted(BuyerAcceptsOfferProtocol.State state);
void onWaitingForUserInteraction(BuyerAcceptsOfferProtocol.State state);
}

View file

@ -36,7 +36,7 @@ public class HandleTakeOfferRequest {
log.trace("Run task");
boolean takeOfferRequestAccepted = tradeState == Trade.State.OPEN;
if (!takeOfferRequestAccepted) {
log.info("Received take offer request but the offer not marked as open anymore.");
log.warn("Received take offer request but the offer not marked as open anymore.");
}
RespondToTakeOfferRequestMessage tradeMessage =
new RespondToTakeOfferRequestMessage(tradeId, takeOfferRequestAccepted);

View file

@ -40,9 +40,6 @@ public class SetupListenerForBlockChainConfirmation {
@Override
public void onConfidenceChanged(Transaction tx, ChangeReason reason) {
log.trace("onConfidenceChanged " + tx.getConfidence());
if (reason == ChangeReason.SEEN_PEERS) {
listener.onDepositTxConfirmedUpdate(tx.getConfidence());
}
if (reason == ChangeReason.TYPE &&
tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) {
listener.onDepositTxConfirmedInBlockchain();

View file

@ -197,6 +197,7 @@ public class SellerTakesOfferProtocol {
if (message.isTakeOfferRequestAccepted()) {
state = State.PayTakeOfferFee;
listener.onTakeOfferRequestAccepted(trade);
PayTakeOfferFee.run(this::onResultPayTakeOfferFee, this::onFault, walletFacade, tradeId);
}
else {
@ -319,7 +320,9 @@ public class SellerTakesOfferProtocol {
log.debug("state " + state);
checkState(state.ordinal() >= State.SendSignedTakerDepositTxAsHex.ordinal());
checkArgument(tradeId.equals(message.getTradeId()));
listener.onDepositTxPublished(walletFacade.takerCommitDepositTx(message.getDepositTxAsHex()));
//TODO takerCommitDepositTx should be in task as well, but will be probably changed anyway when akka is used...
Transaction tx = walletFacade.takerCommitDepositTx(message.getDepositTxAsHex());
listener.onDepositTxPublished(tx);
}
@ -378,9 +381,9 @@ public class SellerTakesOfferProtocol {
offererPayoutAddress);
}
public void onResultSignAndPublishPayoutTx(String transactionId, String payoutTxAsHex) {
public void onResultSignAndPublishPayoutTx(Transaction transaction, String payoutTxAsHex) {
log.debug("onResultSignAndPublishPayoutTx called " + step++);
listener.onPayoutTxPublished(trade, transactionId);
listener.onPayoutTxPublished(trade, transaction);
state = State.SendPayoutTxToOfferer;
SendPayoutTxToOfferer.run(this::onResultSendPayoutTxToOfferer, this::onFault, peerAddress, messageFacade,

View file

@ -19,12 +19,14 @@ package io.bitsquare.trade.protocol.trade.taker;
import io.bitsquare.trade.Trade;
import com.google.bitcoin.core.Transaction;
public interface SellerTakesOfferProtocolListener {
void onDepositTxPublished(String depositTxId);
void onDepositTxPublished(Transaction depositTx);
void onBankTransferInited(String tradeId);
void onPayoutTxPublished(Trade trade, String hashAsString);
void onPayoutTxPublished(Trade trade, Transaction payoutTx);
void onFault(Throwable throwable, SellerTakesOfferProtocol.State state);
@ -32,5 +34,8 @@ public interface SellerTakesOfferProtocolListener {
void onCompleted(SellerTakesOfferProtocol.State state);
void onTakeOfferRequestAccepted(Trade trade);
void onTakeOfferRequestRejected(Trade trade);
}

View file

@ -57,7 +57,7 @@ public class SignAndPublishPayoutTx {
public void onSuccess(Transaction transaction) {
log.debug("takerSignsAndSendsTx " + transaction);
String payoutTxAsHex = Utils.HEX.encode(transaction.bitcoinSerialize());
resultHandler.onResult(transaction.getHashAsString(), payoutTxAsHex);
resultHandler.onResult(transaction, payoutTxAsHex);
}
@Override
@ -73,7 +73,7 @@ public class SignAndPublishPayoutTx {
}
public interface ResultHandler {
void onResult(String transactionId, String payoutTxAsHex);
void onResult(Transaction transaction, String payoutTxAsHex);
}
}

View file

@ -75,7 +75,7 @@ public class AccountSettingsUITestRunner extends Application {
refreshStylesheets();
} catch (IOException e) {
e.printStackTrace();
log.error(e.getStackTrace().toString());
e.printStackTrace();
}
}

View file

@ -75,7 +75,7 @@ public class AccountUITestRunner extends Application {
refreshStylesheets();
} catch (IOException e) {
e.printStackTrace();
log.error(e.getStackTrace().toString());
e.printStackTrace();
}
}

View file

@ -75,7 +75,7 @@ public class RegistrationUITestRunner extends Application {
refreshStylesheets();
} catch (IOException e) {
e.printStackTrace();
log.error(e.getStackTrace().toString());
e.printStackTrace();
}
}

View file

@ -75,7 +75,7 @@ public class SetupUITestRunner extends Application {
refreshStylesheets();
} catch (IOException e) {
e.printStackTrace();
log.error(e.getStackTrace().toString());
e.printStackTrace();
}
}

View file

@ -0,0 +1,104 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.orders.pending;
import io.bitsquare.di.BitSquareModule;
import io.bitsquare.util.ViewLoader;
import com.google.inject.Guice;
import com.google.inject.Injector;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* For testing single isolated UI screens
*/
public class PendingTradesUIRunner extends Application {
private static final Logger log = LoggerFactory.getLogger(PendingTradesUIRunner.class);
private Scene scene;
private Parent view;
private Pane pane;
private boolean devTest = true;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws IOException {
Injector injector = Guice.createInjector(new BitSquareModule());
ViewLoader.setInjector(injector);
pane = new StackPane();
scene = new Scene(pane, 1000, 630);
scene.getAccelerators().put(KeyCombination.valueOf("Shortcut+S"), this::loadMainWindow);
loadMainWindow();
primaryStage.setScene(scene);
primaryStage.show();
}
public void loadMainWindow() {
log.debug("re load");
pane.getChildren().removeAll();
ViewLoader loader = new ViewLoader(
getUrl("/io/bitsquare/gui/main/orders/pending/PendingTradesView.fxml"), false);
try {
view = loader.load();
} catch (IOException e) {
e.printStackTrace();
}
pane.getChildren().setAll(view);
refreshStylesheets();
}
private void refreshStylesheets() {
scene.getStylesheets().clear();
scene.getStylesheets().setAll(getUrl("/io/bitsquare/gui/bitsquare.css").toExternalForm());
}
private URL getUrl(String subPath) {
if (devTest) {
try {
// load from file system location to make a reload possible. makes dev process easier with hot reload
return new URL("file:///Users/mk/Documents/_intellij/bitsquare/src/main/java" + subPath);
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
}
}
else {
return getClass().getResource(subPath);
}
}
}

View file

@ -15,41 +15,33 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.orders;
package io.bitsquare.gui.main.orders.pending.uimock;
import io.bitsquare.gui.CachedViewController;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.components.CachingTabPane;
import io.bitsquare.persistence.Persistence;
import io.bitsquare.gui.components.processbar.ProcessStepBar;
import io.bitsquare.gui.components.processbar.ProcessStepItem;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javax.inject.Inject;
import javafx.fxml.Initializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OrdersController extends CachedViewController {
private static final Logger log = LoggerFactory.getLogger(OrdersController.class);
private static OrdersController INSTANCE;
private final Persistence persistence;
@Inject
private OrdersController(Persistence persistence) {
this.persistence = persistence;
INSTANCE = this;
}
public class PendingTradesControllerUIMock extends CachedViewController {
private static final Logger log = LoggerFactory.getLogger(PendingTradesControllerUIMock.class);
public ProcessStepBar processBar;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public static OrdersController GET_INSTANCE() {
return INSTANCE;
@Inject
public PendingTradesControllerUIMock() {
}
@ -61,8 +53,13 @@ public class OrdersController extends CachedViewController {
public void initialize(URL url, ResourceBundle rb) {
super.initialize(url, rb);
((CachingTabPane) root).initialize(this, persistence, Navigation.Item.OFFER.getFxmlUrl(),
Navigation.Item.PENDING_TRADE.getFxmlUrl(), Navigation.Item.CLOSED_TRADE.getFxmlUrl());
List<ProcessStepItem> items = new ArrayList<>();
items.add(new ProcessStepItem("Deposit TX published"));
items.add(new ProcessStepItem("Waiting for other trader"));
items.add(new ProcessStepItem("Waiting for payment"));
items.add(new ProcessStepItem("Payment received"));
processBar.setProcessStepItems(items);
// processBar.next();
}
@Override
@ -77,25 +74,14 @@ public class OrdersController extends CachedViewController {
///////////////////////////////////////////////////////////////////////////////////////////
// Navigation
// GUI handlers
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public Initializable loadViewAndGetChildController(Navigation.Item item) {
childController = ((CachingTabPane) root).loadViewAndGetChildController(item.getFxmlUrl());
return childController;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public Methods
// Private methods
///////////////////////////////////////////////////////////////////////////////////////////
public void setSelectedTabIndex(int index) {
log.trace("setSelectedTabIndex " + index);
((CachingTabPane) root).setSelectedTabIndex(index);
persistence.write(this, "selectedTabIndex", index);
}
}

View file

@ -0,0 +1,104 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.orders.pending.uimock;
import io.bitsquare.di.BitSquareModule;
import io.bitsquare.util.ViewLoader;
import com.google.inject.Guice;
import com.google.inject.Injector;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* For testing single isolated UI screens
*/
public class PendingTradesUIMockRunner extends Application {
private static final Logger log = LoggerFactory.getLogger(PendingTradesUIMockRunner.class);
private Scene scene;
private Parent view;
private Pane pane;
private boolean devTest = true;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws IOException {
Injector injector = Guice.createInjector(new BitSquareModule());
ViewLoader.setInjector(injector);
pane = new StackPane();
scene = new Scene(pane, 1000, 630);
scene.getAccelerators().put(KeyCombination.valueOf("Shortcut+S"), this::loadMainWindow);
loadMainWindow();
primaryStage.setScene(scene);
primaryStage.show();
}
public void loadMainWindow() {
log.debug("re load");
pane.getChildren().removeAll();
ViewLoader loader = new ViewLoader(
getUrl("/io/bitsquare/gui/main/orders/pending/uimock/PendingTradesViewUIMock.fxml"), false);
try {
view = loader.load();
} catch (IOException e) {
e.printStackTrace();
}
pane.getChildren().setAll(view);
refreshStylesheets();
}
private void refreshStylesheets() {
scene.getStylesheets().clear();
scene.getStylesheets().setAll(getUrl("/io/bitsquare/gui/bitsquare.css").toExternalForm());
}
private URL getUrl(String subPath) {
if (devTest) {
try {
// load from file system location to make a reload possible. makes dev process easier with hot reload
return new URL("file:///Users/mk/Documents/_intellij/bitsquare/src/test/java" + subPath);
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
}
}
else {
return getClass().getResource(subPath);
}
}
}

View file

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ This file is part of Bitsquare.
~
~ Bitsquare is free software: you can redistribute it and/or modify it
~ under the terms of the GNU Affero General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or (at
~ your option) any later version.
~
~ Bitsquare is distributed in the hope that it will be useful, but WITHOUT
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
~ License for more details.
~
~ You should have received a copy of the GNU Affero General Public License
~ along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
-->
<?import io.bitsquare.gui.components.processbar.ProcessStepBar?>
<?import io.bitsquare.gui.components.TitledGroupBg?>
<?import io.bitsquare.gui.components.TitledSeparator?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane fx:id="root" fx:controller="io.bitsquare.gui.main.orders.pending.uimock.PendingTradesControllerUIMock"
hgap="5.0" vgap="5" stylesheets="@../../../../../../../../../main/java/io/bitsquare/gui/bitsquare.css"
xmlns:fx="http://javafx.com/fxml">
<padding>
<Insets bottom="20.0" left="25.0" top="30.0" right="25"/>
</padding>
<TitledSeparator text="Pending trades" GridPane.rowIndex="0" GridPane.columnIndex="0"
GridPane.columnSpan="2"/>
<TableView fx:id="orderBookTable" GridPane.rowIndex="0" GridPane.columnIndex="0" GridPane.columnSpan="2"
prefHeight="150">
<GridPane.margin>
<Insets top="10.0" left="-10" right="-10"/>
</GridPane.margin>
<columns>
<TableColumn text="Amount in BTC (Min.)" fx:id="amountColumn" minWidth="130"/>
<TableColumn text="Price" fx:id="priceColumn" minWidth="130"/>
<TableColumn text="Amount in EUR (Min.)" fx:id="volumeColumn" minWidth="130"/>
<TableColumn text="Country" fx:id="countryColumn" minWidth="60"/>
<TableColumn text="Bank transfer type" fx:id="bankAccountTypeColumn" minWidth="130"/>
<TableColumn text="" fx:id="directionColumn" minWidth="80" sortable="false"/>
</columns>
</TableView>
<ProcessStepBar fx:id="processBar" GridPane.columnSpan="2" GridPane.rowIndex="1" snapToPixel="true">
<GridPane.margin>
<Insets top="30.0" bottom="-10" left="-10" right="-10"/>
</GridPane.margin>
</ProcessStepBar>
<TitledGroupBg fx:id="priceAmountPane" text="Pending trade"
GridPane.rowSpan="2" GridPane.columnSpan="2" GridPane.rowIndex="2">
<GridPane.margin>
<Insets top="40.0" bottom="-10" left="-10" right="-10"/>
</GridPane.margin>
</TitledGroupBg>
<Label text="Status:" GridPane.rowIndex="2">
<GridPane.margin>
<Insets top="50.0"/>
</GridPane.margin>
</Label>
<TextField disable="true" GridPane.rowIndex="2" GridPane.columnIndex="1" text="Blabal">
<GridPane.margin>
<Insets top="50.0"/>
</GridPane.margin>
</TextField>
<Label text="Deposit transaction ID:" GridPane.rowIndex="3"/>
<TextField disable="true" GridPane.rowIndex="3" GridPane.columnIndex="1" text="324dsfsdffdafsdfasdf324"/>
<!--
<InfoDisplay gridPane="root" rowIndex="3"
text="%createOffer.amountPriceBox.info"/>
-->
<columnConstraints>
<ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" minWidth="200"/>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
<rowConstraints>
<RowConstraints/>
<RowConstraints/>
<RowConstraints/>
<RowConstraints/>
</rowConstraints>
</GridPane>

View file

@ -75,7 +75,7 @@ public class FiatAccountUITestRunner extends Application {
refreshStylesheets();
} catch (IOException e) {
e.printStackTrace();
log.error(e.getStackTrace().toString());
e.printStackTrace();
}
}

View file

@ -75,7 +75,7 @@ public class PasswordUITestRunner extends Application {
refreshStylesheets();
} catch (IOException e) {
e.printStackTrace();
log.error(e.getStackTrace().toString());
e.printStackTrace();
}
}

View file

@ -75,7 +75,7 @@ public class RegistrationUITestRunner extends Application {
refreshStylesheets();
} catch (IOException e) {
e.printStackTrace();
log.error(e.getStackTrace().toString());
e.printStackTrace();
}
}

View file

@ -75,7 +75,7 @@ public class RestrictionsUITestRunner extends Application {
refreshStylesheets();
} catch (IOException e) {
e.printStackTrace();
log.error(e.getStackTrace().toString());
e.printStackTrace();
}
}

View file

@ -75,7 +75,7 @@ public class SeedWordsUITestRunner extends Application {
refreshStylesheets();
} catch (IOException e) {
e.printStackTrace();
log.error(e.getStackTrace().toString());
e.printStackTrace();
}
}

View file

@ -23,7 +23,7 @@
<?import javafx.scene.layout.*?>
<GridPane hgap="5.0" vgap="5.0" fx:id="root"
fx:controller="io.bitsquare.gui.main.settings.uimock.BankAccountSettingsControllerUIMock"
stylesheets="@../../../../../../../main/java/io/bitsquare/gui/bitsquare.css"
stylesheets="@../../../../../../../../main/java/io/bitsquare/gui/bitsquare.css"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0"
xmlns:fx="http://javafx.com/fxml">

View file

@ -75,7 +75,7 @@ public class CreateOfferUITestRunner extends Application {
refreshStylesheets();
} catch (IOException e) {
e.printStackTrace();
log.error(e.getStackTrace().toString());
e.printStackTrace();
}
}

View file

@ -72,7 +72,7 @@ public class CreateOfferControllerUIMock implements Initializable {
@Override
public void initialize(URL url, ResourceBundle rb) {
/*
paymentInfoPane.setVisible(false);
collateralLabel.setVisible(false);
collateralTextField.setVisible(false);
@ -114,7 +114,7 @@ public class CreateOfferControllerUIMock implements Initializable {
bankAccountCountyLabel.setVisible(false);
bankAccountCountyTextField.setVisible(false);
showDetailsInfoIcon.setVisible(false);
showDetailsInfoLabel.setVisible(false);
showDetailsInfoLabel.setVisible(false);*/
}
/* @FXML

View file

@ -68,7 +68,7 @@ public class CreateOfferUIMockRunner extends Application {
log.debug("re load");
pane.getChildren().removeAll();
ViewLoader loader = new ViewLoader(
getUrl("/io/bitsquare/gui/trade/createoffer/uimock/CreateOfferViewUIMock.fxml"), false);
getUrl("/io/bitsquare/gui/main/trade/createoffer/uimock/CreateOfferViewUIMock.fxml"), false);
try {
view = loader.load();

View file

@ -23,7 +23,7 @@
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<AnchorPane fx:id="root" prefHeight="630.0" prefWidth="1000.0" style="-fx-background-color: f4f4f4;"
stylesheets="@../../../../../../../../main/java/io/bitsquare/gui/bitsquare.css"
stylesheets="@../../../../../../../../../main/java/io/bitsquare/gui/bitsquare.css"
AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0"
AnchorPane.topAnchor="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="io.bitsquare.gui.main.trade.createoffer.uimock.CreateOfferControllerUIMock">
@ -52,7 +52,8 @@
<children>
<ImageView fitHeight="54.0" fitWidth="62.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../../../../../../../../main/resources/images/buy_black_62_54.png"/>
<Image
url="@../../../../../../../../../main/resources/images/buy_large.png"/>
</image>
</ImageView>
<Label fx:id="buyLabel" alignment="CENTER"
@ -87,7 +88,7 @@
</VBox>
<Label text="x">
<font>
<Font name="Helvetica" size="20.0"/>
<Font name="Helvetica-Bold" size="20.0"/>
</font>
<padding>
<Insets top="14.0"/>
@ -111,7 +112,7 @@
<Label text="=">
<font>
<Font name="Helvetica" size="20.0"/>
<Font name="Helvetica-Bold" size="20.0"/>
</font>
<padding>
<Insets top="14.0"/>
@ -161,7 +162,7 @@
preserveRatio="true" GridPane.rowIndex="2" GridPane.valignment="TOP">
<image>
<Image fx:id="infoIcon"
url="@../../../../../../../../main/resources/images/info.png"/>
url="@../../../../../../../../../main/resources/images/info.png"/>
</image>
<GridPane.margin>
<Insets right="2.0" top="4.0"/>