offer creation screen, model updates, confirm comp.

This commit is contained in:
Manfred Karrer 2014-04-30 02:19:36 +02:00
parent a3bee7652b
commit 3f398755ad
53 changed files with 1261 additions and 1297 deletions

View file

@ -12,15 +12,15 @@ We use bitcoinj library as a submodule. To get the project with the submodule in
git clone --recursive git://github.com/bitsquare/bitsquare git clone --recursive git://github.com/bitsquare/bitsquare
### Implemented (prototype level): ### Implemented (prototype level):
* Screen for orderbook with filtering mock offers by amount, price and order type (buy, sell), other filters not impl. yet * Screen for orderbook with filtering mock offers by amount, price and order type (buy, sell)
* Screen for creating an offer (needs update) * Screen for creating an offer
* Screen for offer taking and payment process * Screen for offer taking and payment process (needs update)
* Simple storage for some filter attributes * Simple persistence
* bitcoinj/wallet integration (basic) * bitcoinj integration
* Setup with account registration and tx with OP_RETURN + embedded and blinded bank account data
* Offer fee payment with a OP_RETURN tx and fees to miners
### Next steps: ### Next steps:
* Setup with account registration
* Other trade variants (Buy BTC taker, Sell BTC offerer, Sell BTC offerer) * Other trade variants (Buy BTC taker, Sell BTC offerer, Sell BTC offerer)
* Arbitrator integration * Arbitrator integration
* Messaging system * Messaging system
@ -28,7 +28,14 @@ git clone --recursive git://github.com/bitsquare/bitsquare
### Screenshots of basic screens: ### Screenshots of basic screens:
* [Registration screen 1](https://github.com/bitsquare/bitsquare/tree/master/screenshots/reg1.png)
* [Registration screen 2](https://github.com/bitsquare/bitsquare/tree/master/screenshots/reg2.png)
* [Registration screen 3](https://github.com/bitsquare/bitsquare/tree/master/screenshots/reg3.png)
* [Orderbook screen 1](https://github.com/bitsquare/bitsquare/tree/master/screenshots/orderbook1.png)
* [Orderbook screen 2](https://github.com/bitsquare/bitsquare/tree/master/screenshots/orderbook2.png)
* [Orderbook screen](https://github.com/bitsquare/bitsquare/tree/master/screenshots/orderbook.png) * [Orderbook screen](https://github.com/bitsquare/bitsquare/tree/master/screenshots/orderbook.png)
* [Create Offer screen 1](https://github.com/bitsquare/bitsquare/tree/master/screenshots/newOffer1.png)
* [Create Offer screen 2](https://github.com/bitsquare/bitsquare/tree/master/screenshots/newOffer2.png)
* [Trade screen](https://github.com/bitsquare/bitsquare/tree/master/screenshots/trade.png) * [Trade screen](https://github.com/bitsquare/bitsquare/tree/master/screenshots/trade.png)
* [Bank transfer screen](https://github.com/bitsquare/bitsquare/tree/master/screenshots/bank_transfer.png) * [Bank transfer screen](https://github.com/bitsquare/bitsquare/tree/master/screenshots/bank_transfer.png)
* [Trade completed screen](https://github.com/bitsquare/bitsquare/tree/master/screenshots/completed.png) * [Trade completed screen](https://github.com/bitsquare/bitsquare/tree/master/screenshots/completed.png)

13
TODO.txt Normal file
View file

@ -0,0 +1,13 @@
- payment process update with new models
- btc payments in payment process
- arbitration integration
Messaging!
low prio:
- add settings after setup
- settings screen
- return to setup when unregistered, change/add bank accounts from settings

BIN
screenshots/newOffer1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
screenshots/newOffer2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

BIN
screenshots/orderbook1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

BIN
screenshots/orderbook2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
screenshots/reg1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
screenshots/reg2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
screenshots/reg3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
screenshots/reg4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View file

@ -6,7 +6,7 @@ import io.bitsquare.btc.WalletFacade;
import io.bitsquare.di.BitSquareModule; import io.bitsquare.di.BitSquareModule;
import io.bitsquare.di.GuiceFXMLLoader; import io.bitsquare.di.GuiceFXMLLoader;
import io.bitsquare.gui.util.Localisation; import io.bitsquare.gui.util.Localisation;
import io.bitsquare.settings.Startup; import io.bitsquare.settings.Settings;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import javafx.application.Application; import javafx.application.Application;
@ -16,6 +16,8 @@ import javafx.stage.Stage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Locale;
public class BitSquare extends Application public class BitSquare extends Application
{ {
private static final Logger log = LoggerFactory.getLogger(BitSquare.class); private static final Logger log = LoggerFactory.getLogger(BitSquare.class);
@ -34,24 +36,30 @@ public class BitSquare extends Application
// apply stored data // apply stored data
final User user = injector.getInstance(User.class); final User user = injector.getInstance(User.class);
final Settings settings = injector.getInstance(Settings.class);
final Storage storage = injector.getInstance(Storage.class); final Storage storage = injector.getInstance(Storage.class);
user.updateFromStorage((User) storage.read(user.getClass().getName())); user.updateFromStorage((User) storage.read(user.getClass().getName()));
//TODO remove settings.updateFromStorage((Settings) storage.read(settings.getClass().getName()));
final Startup setup = injector.getInstance(Startup.class); initSettings(settings, storage);
setup.applyPersistedData();
stage.setTitle("BitSquare"); stage.setTitle("BitSquare");
GuiceFXMLLoader.setInjector(injector); GuiceFXMLLoader.setInjector(injector);
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource("/io/bitsquare/gui/MainView.fxml"), Localisation.getResourceBundle()); final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource("/io/bitsquare/gui/MainView.fxml"), Localisation.getResourceBundle());
final Parent mainView = loader.load(); final Parent mainView = loader.load();
final Scene scene = new Scene(mainView, 800, 600); final Scene scene = new Scene(mainView, 800, 600);
stage.setScene(scene); stage.setScene(scene);
final String global = getClass().getResource("/io/bitsquare/gui/global.css").toExternalForm(); final String global = getClass().getResource("/io/bitsquare/gui/global.css").toExternalForm();
scene.getStylesheets().setAll(global); scene.getStylesheets().setAll(global);
stage.setMinWidth(740);
stage.setMinHeight(400);
stage.setWidth(800);
stage.setHeight(600);
stage.show(); stage.show();
} }
@ -62,4 +70,31 @@ public class BitSquare extends Application
super.stop(); super.stop();
} }
private void initSettings(Settings settings, Storage storage)
{
Settings savedSettings = (Settings) storage.read(settings.getClass().getName());
if (savedSettings == null)
{
settings.getAcceptedCountryLocales().clear();
settings.getAcceptedLanguageLocales().clear();
settings.addAcceptedLanguageLocale(Locale.getDefault());
settings.addAcceptedCountryLocale(Locale.getDefault());
//TODO mock
settings.addAcceptedLanguageLocale(new Locale("en", "US"));
settings.addAcceptedLanguageLocale(new Locale("es", "ES"));
settings.addAcceptedCountryLocale(new Locale("de", "AT"));
settings.addAcceptedCountryLocale(new Locale("en", "US"));
settings.addAcceptedCountryLocale(new Locale("es", "ES"));
storage.write(settings.getClass().getName(), settings);
}
else
{
settings.updateFromStorage(savedSettings);
}
}
} }

View file

@ -18,23 +18,26 @@ public class BankAccount implements Serializable
private Currency currency; private Currency currency;
private String uid; private String uid;
// TODO just for mock yet
public BankAccount(BankAccountType bankAccountType) private String accountTitle;
{
this.bankAccountType = bankAccountType; public BankAccount(BankAccountType bankAccountType,
Currency currency,
} Locale countryLocale,
String accountTitle,
public BankAccount(BankAccountType bankAccountType, String accountPrimaryID, String accountSecondaryID, String accountHolderName, Locale countryLocale, Currency currency) String accountHolderName,
String accountPrimaryID,
String accountSecondaryID)
{ {
this.bankAccountType = bankAccountType; this.bankAccountType = bankAccountType;
this.currency = currency;
this.countryLocale = countryLocale;
this.accountTitle = accountTitle;
this.accountHolderName = accountHolderName;
this.accountPrimaryID = accountPrimaryID; this.accountPrimaryID = accountPrimaryID;
this.accountSecondaryID = accountSecondaryID; this.accountSecondaryID = accountSecondaryID;
this.accountHolderName = accountHolderName;
this.countryLocale = countryLocale;
this.currency = currency;
uid = bankAccountType + "_" + accountPrimaryID + "_" + accountSecondaryID + "_" + accountHolderName + "_" + countryLocale.getISO3Country(); uid = bankAccountType + "_" + accountPrimaryID + "_" + accountSecondaryID + "_" + accountHolderName + "_" + countryLocale.getCountry();
} }
public String getAccountPrimaryID() public String getAccountPrimaryID()
@ -72,6 +75,11 @@ public class BankAccount implements Serializable
return uid; return uid;
} }
public String getAccountTitle()
{
return accountTitle;
}
// Changes of that structure must be reflected in VERSION updates // Changes of that structure must be reflected in VERSION updates
public String getStringifiedBankAccount() public String getStringifiedBankAccount()
{ {
@ -81,15 +89,9 @@ public class BankAccount implements Serializable
", secondaryID='" + accountSecondaryID + '\'' + ", secondaryID='" + accountSecondaryID + '\'' +
", holderName='" + accountHolderName + '\'' + ", holderName='" + accountHolderName + '\'' +
", currency='" + currency.getCurrencyCode() + '\'' + ", currency='" + currency.getCurrencyCode() + '\'' +
", country='" + countryLocale.getISO3Country() + '\'' + ", country='" + countryLocale.getCountry() + '\'' +
", v='" + VERSION + '\'' + ", v='" + VERSION + '\'' +
'}'; '}';
} }
public String getShortName()
{
return bankAccountType + " " + accountPrimaryID + " / " + accountSecondaryID + " / " + currency.getCurrencyCode();
}
} }

View file

@ -170,7 +170,7 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx)
{ {
for (WalletFacade.WalletListener walletListener : walletListeners) for (WalletFacade.WalletListener walletListener : walletListeners)
walletListener.onConfidenceChanged(tx.getConfidence().numBroadcastPeers(), WalletUtil.getConfirmationDepthInBlocks(this)); walletListener.onConfidenceChanged(tx.getConfidence().numBroadcastPeers(), WalletUtil.getConfDepthInBlocks(this));
log.info("onTransactionConfidenceChanged " + tx.getConfidence().toString()); log.info("onTransactionConfidenceChanged " + tx.getConfidence().toString());
} }
@ -205,7 +205,7 @@ public class AccountRegistrationWallet extends Wallet implements WalletEventList
log.info("onScriptsAdded"); log.info("onScriptsAdded");
} }
int getConfirmationNumBroadcastPeers() int getConfNumBroadcastPeers()
{ {
Transaction transaction = WalletUtil.getTransaction(this); Transaction transaction = WalletUtil.getTransaction(this);
return (transaction == null || transaction.getConfidence() == null) ? 0 : transaction.getConfidence().numBroadcastPeers(); return (transaction == null || transaction.getConfidence() == null) ? 0 : transaction.getConfidence().numBroadcastPeers();

View file

@ -8,7 +8,6 @@ public class Fees
{ {
public static BigInteger ACCOUNT_REGISTRATION_FEE = Transaction.MIN_NONDUST_OUTPUT;// Utils.toNanoCoins("0.001"); public static BigInteger ACCOUNT_REGISTRATION_FEE = Transaction.MIN_NONDUST_OUTPUT;// Utils.toNanoCoins("0.001");
public static BigInteger OFFER_CREATION_FEE = new BigInteger("500000"); public static BigInteger OFFER_CREATION_FEE = Transaction.MIN_NONDUST_OUTPUT; // Utils.toNanoCoins("0.001");
public static BigInteger OFFER_TAKER_FEE = OFFER_CREATION_FEE; public static BigInteger OFFER_TAKER_FEE = OFFER_CREATION_FEE;
public static BigInteger BTC_NETWORK_FEE = new BigInteger("10000");
} }

View file

@ -5,7 +5,10 @@ import com.google.bitcoin.kits.WalletAppKit;
import com.google.bitcoin.params.MainNetParams; import com.google.bitcoin.params.MainNetParams;
import com.google.bitcoin.params.RegTestParams; import com.google.bitcoin.params.RegTestParams;
import com.google.bitcoin.script.Script; import com.google.bitcoin.script.Script;
import com.google.bitcoin.script.ScriptBuilder;
import com.google.bitcoin.utils.Threading; import com.google.bitcoin.utils.Threading;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bitsquare.crypto.CryptoFacade; import io.bitsquare.crypto.CryptoFacade;
import javafx.application.Platform; import javafx.application.Platform;
@ -18,6 +21,8 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import static com.google.bitcoin.script.ScriptOpCodes.OP_RETURN;
/** /**
* That facade delivers wallet functionality from the bitcoinJ library * That facade delivers wallet functionality from the bitcoinJ library
* Code from BitcoinJ must not be used outside that facade. * Code from BitcoinJ must not be used outside that facade.
@ -79,12 +84,12 @@ public class WalletFacade implements WalletEventListener
walletAppKit.startAsync(); walletAppKit.startAsync();
walletAppKit.awaitRunning(); walletAppKit.awaitRunning();
// Don't make the user wait for confirmations for now, as the intention is they're sending it their own money! // Don't make the user wait for confirmations for now, as the intention is they're sending it their own money!
walletAppKit.wallet().allowSpendingUnconfirmedTransactions(); getWallet().allowSpendingUnconfirmedTransactions();
walletAppKit.peerGroup().setMaxConnections(11); walletAppKit.peerGroup().setMaxConnections(11);
walletAppKit.wallet().addEventListener(this); getWallet().addEventListener(this);
log.info(walletAppKit.wallet().toString()); log.info(getWallet().toString());
} }
public void shutDown() public void shutDown()
@ -134,12 +139,12 @@ public class WalletFacade implements WalletEventListener
public BigInteger getBalance() public BigInteger getBalance()
{ {
return walletAppKit.wallet().getBalance(Wallet.BalanceType.ESTIMATED); return getWallet().getBalance(Wallet.BalanceType.ESTIMATED);
} }
public String getAddress() public String getAddress()
{ {
return walletAppKit.wallet().getKeys().get(0).toAddress(networkParameters).toString(); return getWallet().getKeys().get(0).toAddress(networkParameters).toString();
} }
// account registration // account registration
@ -171,14 +176,14 @@ public class WalletFacade implements WalletEventListener
&& blockChainFacade.verifyAddressInBlockChain(hashAsHexStringToVerify, address); && blockChainFacade.verifyAddressInBlockChain(hashAsHexStringToVerify, address);
} }
public int getRegistrationConfirmationNumBroadcastPeers() public int getRegConfNumBroadcastPeers()
{ {
return getAccountRegistrationWallet().getConfirmationNumBroadcastPeers(); return getAccountRegistrationWallet().getConfNumBroadcastPeers();
} }
public int getRegistrationConfirmationDepthInBlocks() public int getRegConfDepthInBlocks()
{ {
return WalletUtil.getConfirmationDepthInBlocks(getAccountRegistrationWallet()); return WalletUtil.getConfDepthInBlocks(getAccountRegistrationWallet());
} }
// WalletEventListener // WalletEventListener
@ -195,7 +200,7 @@ public class WalletFacade implements WalletEventListener
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx)
{ {
for (WalletListener walletListener : walletListeners) for (WalletListener walletListener : walletListeners)
walletListener.onConfidenceChanged(tx.getConfidence().numBroadcastPeers(), WalletUtil.getConfirmationDepthInBlocks(walletAppKit.wallet())); walletListener.onConfidenceChanged(tx.getConfidence().numBroadcastPeers(), WalletUtil.getConfDepthInBlocks(getWallet()));
log.info("onTransactionConfidenceChanged " + tx.getConfidence().toString()); log.info("onTransactionConfidenceChanged " + tx.getConfidence().toString());
} }
@ -239,6 +244,51 @@ public class WalletFacade implements WalletEventListener
return accountRegistrationWallet; return accountRegistrationWallet;
} }
public String payOfferFee() throws InsufficientMoneyException
{
getWallet();
Script script = new ScriptBuilder()
.op(OP_RETURN)
.build();
Transaction transaction = new Transaction(networkParameters);
TransactionOutput dataOutput = new TransactionOutput(networkParameters,
transaction,
Transaction.MIN_NONDUST_OUTPUT,
script.getProgram());
transaction.addOutput(dataOutput);
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(transaction);
// give fee to miners yet. Later it could be spent to other traders via lottery...
sendRequest.fee = Fees.OFFER_CREATION_FEE;
Wallet.SendResult sendResult = getWallet().sendCoins(sendRequest);
Futures.addCallback(sendResult.broadcastComplete, new FutureCallback<Transaction>()
{
@Override
public void onSuccess(Transaction result)
{
log.info("sendResult onSuccess:" + result.toString());
// Platform.runLater(overlayUi::done);
}
@Override
public void onFailure(Throwable t)
{
log.warn("sendResult onFailure:" + t.toString());
// We died trying to empty the wallet.
// crashAlert(t);
}
});
return transaction.getHashAsString();
}
private Wallet getWallet()
{
return walletAppKit.wallet();
}
// inner classes // inner classes
private class BlockChainDownloadListener extends com.google.bitcoin.core.DownloadListener private class BlockChainDownloadListener extends com.google.bitcoin.core.DownloadListener

View file

@ -11,7 +11,7 @@ public class WalletUtil
{ {
// TODO check if that is correct and safe // TODO check if that is correct and safe
public static int getConfirmationDepthInBlocks(Wallet wallet) public static int getConfDepthInBlocks(Wallet wallet)
{ {
Transaction transaction = WalletUtil.getTransaction(wallet); Transaction transaction = WalletUtil.getTransaction(wallet);
if (transaction != null && transaction.getConfidence() != null) if (transaction != null && transaction.getConfidence() != null)

View file

@ -16,9 +16,9 @@ import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.settings.OrderBookFilterSettings; import io.bitsquare.settings.OrderBookFilterSettings;
import io.bitsquare.settings.Settings; import io.bitsquare.settings.Settings;
import io.bitsquare.settings.Startup;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import io.bitsquare.trade.Trading; import io.bitsquare.trade.Trading;
import io.bitsquare.trade.orderbook.MockOrderBook;
import io.bitsquare.trade.orderbook.OrderBook; import io.bitsquare.trade.orderbook.OrderBook;
import io.bitsquare.trade.orderbook.OrderBookFilter; import io.bitsquare.trade.orderbook.OrderBookFilter;
import io.bitsquare.user.User; import io.bitsquare.user.User;
@ -31,9 +31,8 @@ public class BitSquareModule extends AbstractModule
@Override @Override
protected void configure() protected void configure()
{ {
bind(Startup.class).asEagerSingleton();
bind(User.class).asEagerSingleton(); bind(User.class).asEagerSingleton();
bind(OrderBook.class).asEagerSingleton(); bind(OrderBook.class).to(MockOrderBook.class).asEagerSingleton();
bind(Storage.class).asEagerSingleton(); bind(Storage.class).asEagerSingleton();
bind(Settings.class).asEagerSingleton(); bind(Settings.class).asEagerSingleton();
bind(OrderBookFilter.class).asEagerSingleton(); bind(OrderBookFilter.class).asEagerSingleton();

View file

@ -3,4 +3,5 @@ package io.bitsquare.gui;
public interface ChildController public interface ChildController
{ {
void setNavigationController(NavigationController navigationController); void setNavigationController(NavigationController navigationController);
} }

View file

@ -10,9 +10,7 @@ import io.bitsquare.gui.trade.TradeController;
import io.bitsquare.gui.util.Formatter; import io.bitsquare.gui.util.Formatter;
import io.bitsquare.gui.util.Icons; import io.bitsquare.gui.util.Icons;
import io.bitsquare.gui.util.Localisation; import io.bitsquare.gui.util.Localisation;
import io.bitsquare.settings.Settings;
import io.bitsquare.trade.Direction; import io.bitsquare.trade.Direction;
import io.bitsquare.trade.orderbook.OrderBookFilter;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
@ -39,9 +37,7 @@ public class MainController implements Initializable, NavigationController, Wall
{ {
private static final Logger log = LoggerFactory.getLogger(MainController.class); private static final Logger log = LoggerFactory.getLogger(MainController.class);
private Settings settings;
private User user; private User user;
private OrderBookFilter orderBookFilter;
private WalletFacade walletFacade; private WalletFacade walletFacade;
private ChildController childController; private ChildController childController;
private ToggleGroup toggleGroup; private ToggleGroup toggleGroup;
@ -61,11 +57,9 @@ public class MainController implements Initializable, NavigationController, Wall
public AnchorPane anchorPane; public AnchorPane anchorPane;
@Inject @Inject
public MainController(Settings settings, User user, OrderBookFilter orderBookFilter, WalletFacade walletFacade) public MainController(User user, WalletFacade walletFacade)
{ {
this.settings = settings;
this.user = user; this.user = user;
this.orderBookFilter = orderBookFilter;
this.walletFacade = walletFacade; this.walletFacade = walletFacade;
} }
@ -78,6 +72,7 @@ public class MainController implements Initializable, NavigationController, Wall
walletFacade.addDownloadListener(this); walletFacade.addDownloadListener(this);
walletFacade.initWallet(); walletFacade.initWallet();
buildNavigation(); buildNavigation();
if (user.getAccountID() == null) if (user.getAccountID() == null)
{ {
@ -107,6 +102,11 @@ public class MainController implements Initializable, NavigationController, Wall
return null; return null;
} }
if (childController instanceof TradeController)
{
((TradeController) childController).cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(fxmlView), Localisation.getResourceBundle()); final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(fxmlView), Localisation.getResourceBundle());
try try
{ {
@ -172,7 +172,7 @@ public class MainController implements Initializable, NavigationController, Wall
addNavButton(leftNavPane, "Funds", Icons.FUNDS, Icons.FUNDS, NavigationController.FUNDS); addNavButton(leftNavPane, "Funds", Icons.FUNDS, Icons.FUNDS, NavigationController.FUNDS);
addNavButton(leftNavPane, "Message", Icons.MSG, Icons.MSG, NavigationController.MSG); addNavButton(leftNavPane, "Message", Icons.MSG, Icons.MSG, NavigationController.MSG);
addBalanceInfo(rightNavPane); addBalanceInfo(rightNavPane);
addAccountComboBox(); addAccountComboBox(rightNavPane);
addNavButton(rightNavPane, "Settings", Icons.SETTINGS, Icons.SETTINGS, NavigationController.SETTINGS); addNavButton(rightNavPane, "Settings", Icons.SETTINGS, Icons.SETTINGS, NavigationController.SETTINGS);
@ -226,15 +226,12 @@ public class MainController implements Initializable, NavigationController, Wall
private TextField addBalanceInfo(Pane parent) private TextField addBalanceInfo(Pane parent)
{ {
Pane holder = new Pane();
TextField balanceLabel = new TextField(); TextField balanceLabel = new TextField();
balanceLabel.setEditable(false); balanceLabel.setEditable(false);
balanceLabel.setMouseTransparent(true); balanceLabel.setMouseTransparent(true);
balanceLabel.setPrefWidth(90); balanceLabel.setPrefWidth(90);
balanceLabel.setId("nav-balance-label"); balanceLabel.setId("nav-balance-label");
balanceLabel.setText(Formatter.formatSatoshis(walletFacade.getBalance(), false)); balanceLabel.setText(Formatter.formatSatoshis(walletFacade.getBalance(), false));
holder.getChildren().add(balanceLabel);
rightNavPane.getChildren().add(holder);
Label balanceCurrencyLabel = new Label("BTC"); Label balanceCurrencyLabel = new Label("BTC");
balanceCurrencyLabel.setPadding(new Insets(6, 0, 0, 0)); balanceCurrencyLabel.setPadding(new Insets(6, 0, 0, 0));
@ -256,7 +253,7 @@ public class MainController implements Initializable, NavigationController, Wall
return balanceLabel; return balanceLabel;
} }
private void addAccountComboBox() private void addAccountComboBox(Pane parent)
{ {
if (user.getBankAccounts().size() > 1) if (user.getBankAccounts().size() > 1)
{ {
@ -268,7 +265,7 @@ public class MainController implements Initializable, NavigationController, Wall
@Override @Override
public String toString(BankAccount bankAccount) public String toString(BankAccount bankAccount)
{ {
return bankAccount.getShortName(); return bankAccount.getAccountTitle();
} }
@Override @Override
@ -278,6 +275,16 @@ public class MainController implements Initializable, NavigationController, Wall
} }
}); });
VBox vBox = new VBox();
vBox.setPadding(new Insets(12, 0, 0, 0));
vBox.setSpacing(2);
Label titleLabel = new Label("Bank account");
titleLabel.setMouseTransparent(true);
titleLabel.setPrefWidth(90);
titleLabel.setId("nav-button-label");
vBox.getChildren().setAll(accountComboBox, titleLabel);
parent.getChildren().add(vBox);
accountComboBox.valueProperty().addListener(new ChangeListener<BankAccount>() accountComboBox.valueProperty().addListener(new ChangeListener<BankAccount>()
{ {
@ -285,16 +292,10 @@ public class MainController implements Initializable, NavigationController, Wall
public void changed(ObservableValue ov, BankAccount oldValue, BankAccount newValue) public void changed(ObservableValue ov, BankAccount oldValue, BankAccount newValue)
{ {
user.setCurrentBankAccount(newValue); user.setCurrentBankAccount(newValue);
orderBookFilter.setCurrency(newValue.getCurrency());
orderBookFilter.setCountryLocale(newValue.getCountryLocale());
} }
}); });
Pane holder = new Pane();
holder.getChildren().add(accountComboBox);
rightNavPane.getChildren().add(holder);
} }
} }
} }

View file

@ -1,10 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<StackPane fx:id="rootContainer" minHeight="300" minWidth="400" prefHeight="600" prefWidth="800" <StackPane fx:id="rootContainer" stylesheets="/io/bitsquare/gui/global.css" xmlns:fx="http://javafx.com/fxml/1"
stylesheets="/io/bitsquare/gui/global.css" xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx/8" fx:controller="io.bitsquare.gui.MainController"> xmlns="http://javafx.com/javafx/8" fx:controller="io.bitsquare.gui.MainController">
<AnchorPane fx:id="anchorPane" id="root-pane" minHeight="300" minWidth="400" prefHeight="600" prefWidth="800"> <AnchorPane fx:id="anchorPane" id="root-pane">
<HBox fx:id="leftNavPane" spacing="10" AnchorPane.leftAnchor="0" AnchorPane.topAnchor="0"/> <HBox fx:id="leftNavPane" spacing="10" AnchorPane.leftAnchor="0" AnchorPane.topAnchor="0"/>
<HBox fx:id="rightNavPane" spacing="10" AnchorPane.rightAnchor="10" AnchorPane.topAnchor="0"/> <HBox fx:id="rightNavPane" spacing="10" AnchorPane.rightAnchor="10" AnchorPane.topAnchor="0"/>
<AnchorPane fx:id="contentPane" id="content-pane" AnchorPane.bottomAnchor="20" AnchorPane.leftAnchor="0" <AnchorPane fx:id="contentPane" id="content-pane" AnchorPane.bottomAnchor="20" AnchorPane.leftAnchor="0"

View file

@ -0,0 +1,67 @@
package io.bitsquare.gui.components;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.util.FormBuilder;
import io.bitsquare.gui.util.Icons;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
public class ConfirmationComponent implements WalletFacade.WalletListener
{
private static final Logger log = LoggerFactory.getLogger(ConfirmationComponent.class);
private ImageView confirmIconImageView;
private TextField confirmationsLabel;
private ProgressIndicator confirmSpinner;
public ConfirmationComponent(WalletFacade walletFacade, GridPane gridPane, int row)
{
confirmationsLabel = FormBuilder.addConfirmationsLabel(gridPane, walletFacade, row);
confirmIconImageView = FormBuilder.addConfirmationsIcon(gridPane, walletFacade, row);
confirmSpinner = FormBuilder.addConfirmationsSpinner(gridPane, walletFacade, row);
}
@Override
public void onConfidenceChanged(int numBroadcastPeers, int depthInBlocks)
{
confirmIconImageView.setImage(getConfirmIconImage(numBroadcastPeers, depthInBlocks));
confirmationsLabel.setText(getConfirmationsText(numBroadcastPeers, depthInBlocks));
if (depthInBlocks == 0)
confirmSpinner.setProgress(-1);
else
confirmSpinner.setOpacity(0);
log.info("onConfidenceChanged " + numBroadcastPeers + " / " + depthInBlocks);
}
@Override
public void onCoinsReceived(BigInteger newBalance)
{
log.info("onCoinsReceived " + newBalance);
}
private String getConfirmationsText(int numBroadcastPeers, int depthInBlocks)
{
depthInBlocks = 0;
return depthInBlocks + " confirmation(s) / " + "Seen by " + numBroadcastPeers + " peer(s)";
}
private Image getConfirmIconImage(int numBroadcastPeers, int depthInBlocks)
{
depthInBlocks = 0;
if (depthInBlocks > 0)
return Icons.getIconImage(Icons.getIconIDForConfirmations(depthInBlocks));
else
return Icons.getIconImage(Icons.getIconIDForPeersSeenTx(numBroadcastPeers));
}
}

View file

@ -1,6 +1,6 @@
package io.bitsquare.gui.components.processbar; package io.bitsquare.gui.components.processbar;
import io.bitsquare.gui.util.Utils; import io.bitsquare.gui.util.GUIUtils;
import javafx.animation.AnimationTimer; import javafx.animation.AnimationTimer;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.Control; import javafx.scene.control.Control;
@ -65,7 +65,7 @@ public class ProcessStepsBuilder
// TODO // TODO
// mock simulate network delay // mock simulate network delay
Utils.setTimeout(100, (AnimationTimer animationTimer) -> { GUIUtils.setTimeout(100, (AnimationTimer animationTimer) -> {
next(); next();
return null; return null;
}); });

View file

@ -1,7 +1,11 @@
package io.bitsquare.gui.settings; package io.bitsquare.gui.settings;
import com.google.inject.Inject;
import io.bitsquare.gui.ChildController; import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.NavigationController; import io.bitsquare.gui.NavigationController;
import io.bitsquare.settings.Settings;
import io.bitsquare.storage.Storage;
import io.bitsquare.user.User;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import java.net.URL; import java.net.URL;
@ -9,15 +13,24 @@ import java.util.ResourceBundle;
public class SettingsController implements Initializable, ChildController public class SettingsController implements Initializable, ChildController
{ {
private User user;
private Settings settings;
private Storage storage;
private NavigationController navigationController; private NavigationController navigationController;
@Inject
public SettingsController(User user, Settings settings, Storage storage)
{
this.user = user;
this.settings = settings;
this.storage = storage;
}
@Override @Override
public void initialize(URL url, ResourceBundle rb) public void initialize(URL url, ResourceBundle rb)
{ {
} }
@Override @Override

View file

@ -10,6 +10,7 @@ import io.bitsquare.btc.WalletFacade;
import io.bitsquare.crypto.CryptoFacade; import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.gui.ChildController; import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.NavigationController; import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.components.ConfirmationComponent;
import io.bitsquare.gui.components.NetworkSyncPane; import io.bitsquare.gui.components.NetworkSyncPane;
import io.bitsquare.gui.components.processbar.ProcessStepBar; import io.bitsquare.gui.components.processbar.ProcessStepBar;
import io.bitsquare.gui.components.processbar.ProcessStepItem; import io.bitsquare.gui.components.processbar.ProcessStepItem;
@ -18,11 +19,10 @@ import io.bitsquare.gui.util.Formatter;
import io.bitsquare.settings.Settings; import io.bitsquare.settings.Settings;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import io.bitsquare.util.Utils;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.Clipboard; import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent; import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
@ -48,8 +48,7 @@ public class SetupController implements Initializable, ChildController, WalletFa
private List<ProcessStepItem> processStepItems = new ArrayList(); private List<ProcessStepItem> processStepItems = new ArrayList();
private NavigationController navigationController; private NavigationController navigationController;
private ImageView confirmIconImageView; private TextField balanceLabel, accountTitle, accountHolderName, accountPrimaryID, accountSecondaryID;
private TextField balanceLabel, confirmationsLabel, accountHolderName, accountPrimaryID, accountSecondaryID;
private ComboBox countryComboBox, bankTransferTypeComboBox, currencyComboBox; private ComboBox countryComboBox, bankTransferTypeComboBox, currencyComboBox;
private Button addBankAccountButton; private Button addBankAccountButton;
@ -103,8 +102,7 @@ public class SetupController implements Initializable, ChildController, WalletFa
public void onConfidenceChanged(int numBroadcastPeers, int depthInBlocks) public void onConfidenceChanged(int numBroadcastPeers, int depthInBlocks)
{ {
updateCreateAccountButton(); updateCreateAccountButton();
confirmIconImageView.setImage(getConfirmIconImage(numBroadcastPeers, depthInBlocks));
confirmationsLabel.setText(getConfirmationsText(numBroadcastPeers, depthInBlocks));
log.info("onConfidenceChanged " + numBroadcastPeers + " / " + depthInBlocks); log.info("onConfidenceChanged " + numBroadcastPeers + " / " + depthInBlocks);
} }
@ -133,24 +131,18 @@ public class SetupController implements Initializable, ChildController, WalletFa
return bankTransferTypeComboBox.getSelectionModel().getSelectedItem() != null return bankTransferTypeComboBox.getSelectionModel().getSelectedItem() != null
&& countryComboBox.getSelectionModel().getSelectedItem() != null && countryComboBox.getSelectionModel().getSelectedItem() != null
&& currencyComboBox.getSelectionModel().getSelectedItem() != null && currencyComboBox.getSelectionModel().getSelectedItem() != null
&& accountTitle.getText().length() > 0
&& accountHolderName.getText().length() > 0
&& accountPrimaryID.getText().length() > 0 && accountPrimaryID.getText().length() > 0
&& accountSecondaryID.getText().length() > 0 && accountSecondaryID.getText().length() > 0
&& accountHolderName.getText().length() > 0
&& accountIDsByBankTransferTypeValid; && accountIDsByBankTransferTypeValid;
} }
private Image getConfirmIconImage(int numBroadcastPeers, int depthInBlocks)
{
if (depthInBlocks > 0)
return Icons.getIconImage(Icons.getIconIDForConfirmations(depthInBlocks));
else
return Icons.getIconImage(Icons.getIconIDForPeersSeenTx(numBroadcastPeers));
}
private void updateCreateAccountButton() private void updateCreateAccountButton()
{ {
boolean funded = walletFacade.getAccountRegistrationBalance().compareTo(BigInteger.ZERO) > 0; boolean funded = walletFacade.getAccountRegistrationBalance().compareTo(BigInteger.ZERO) > 0;
nextButton.setDisable(!funded || walletFacade.getRegistrationConfirmationDepthInBlocks() == 0); nextButton.setDisable(!funded || walletFacade.getRegConfDepthInBlocks() == 0);
} }
@ -158,11 +150,6 @@ public class SetupController implements Initializable, ChildController, WalletFa
// GUI BUILDER // GUI BUILDER
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
private String getConfirmationsText(int registrationConfirmationNumBroadcastPeers, int registrationConfirmationDepthInBlocks)
{
return registrationConfirmationDepthInBlocks + " confirmation(s) / " + "Seen by " + registrationConfirmationNumBroadcastPeers + " peer(s)";
}
private void buildStep0() private void buildStep0()
{ {
infoLabel.setText("You need to pay 0.01 BTC to the registration address.\n\n" + infoLabel.setText("You need to pay 0.01 BTC to the registration address.\n\n" +
@ -174,8 +161,7 @@ public class SetupController implements Initializable, ChildController, WalletFa
int gridRow = -1; int gridRow = -1;
TextField addressLabel = FormBuilder.addInputField(formGridPane, "Registration address:", walletFacade.getAccountRegistrationAddress().toString(), ++gridRow); TextField addressLabel = FormBuilder.addTextField(formGridPane, "Registration address:", walletFacade.getAccountRegistrationAddress().toString(), ++gridRow, false, true);
addressLabel.setEditable(false);
Label copyIcon = new Label(""); Label copyIcon = new Label("");
formGridPane.add(copyIcon, 2, gridRow); formGridPane.add(copyIcon, 2, gridRow);
@ -183,14 +169,9 @@ public class SetupController implements Initializable, ChildController, WalletFa
AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY); AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY);
Tooltip.install(copyIcon, new Tooltip("Copy address to clipboard")); Tooltip.install(copyIcon, new Tooltip("Copy address to clipboard"));
balanceLabel = FormBuilder.addInputField(formGridPane, "Balance:", Formatter.formatSatoshis(walletFacade.getAccountRegistrationBalance(), true), ++gridRow); balanceLabel = FormBuilder.addTextField(formGridPane, "Balance:", Formatter.formatSatoshis(walletFacade.getAccountRegistrationBalance(), true), ++gridRow);
balanceLabel.setEditable(false);
confirmationsLabel = FormBuilder.addInputField(formGridPane, "Confirmations:", getConfirmationsText(walletFacade.getRegistrationConfirmationNumBroadcastPeers(), walletFacade.getRegistrationConfirmationDepthInBlocks()), ++gridRow); ConfirmationComponent confirmationComponent = new ConfirmationComponent(walletFacade, formGridPane, ++gridRow);
confirmationsLabel.setEditable(false);
confirmIconImageView = new ImageView(getConfirmIconImage(walletFacade.getRegistrationConfirmationNumBroadcastPeers(), walletFacade.getRegistrationConfirmationDepthInBlocks()));
formGridPane.add(confirmIconImageView, 2, gridRow);
nextButton.setText("Payment done"); nextButton.setText("Payment done");
updateCreateAccountButton(); updateCreateAccountButton();
@ -221,13 +202,29 @@ public class SetupController implements Initializable, ChildController, WalletFa
formGridPane.getChildren().clear(); formGridPane.getChildren().clear();
int gridRow = -1; int gridRow = -1;
bankTransferTypeComboBox = FormBuilder.addComboBox(formGridPane, "Bank account type:", settings.getAllBankAccountTypes(), ++gridRow); bankTransferTypeComboBox = FormBuilder.addComboBox(formGridPane, "Bank account type:", Utils.getAllBankAccountTypes(), ++gridRow);
bankTransferTypeComboBox.setConverter(new StringConverter<BankAccountType>()
{
@Override
public String toString(BankAccountType bankAccountType)
{
return Localisation.get(bankAccountType.toString());
}
@Override
public BankAccountType fromString(String s)
{
return null;
}
});
bankTransferTypeComboBox.setPromptText("Select bank account type"); bankTransferTypeComboBox.setPromptText("Select bank account type");
accountTitle = FormBuilder.addInputField(formGridPane, "Bank account title:", "", ++gridRow);
accountHolderName = FormBuilder.addInputField(formGridPane, "Bank account holder name:", "", ++gridRow); accountHolderName = FormBuilder.addInputField(formGridPane, "Bank account holder name:", "", ++gridRow);
accountPrimaryID = FormBuilder.addInputField(formGridPane, "Bank account primary ID", "", ++gridRow); accountPrimaryID = FormBuilder.addInputField(formGridPane, "Bank account primary ID", "", ++gridRow);
accountSecondaryID = FormBuilder.addInputField(formGridPane, "Bank account secondary ID:", "", ++gridRow); accountSecondaryID = FormBuilder.addInputField(formGridPane, "Bank account secondary ID:", "", ++gridRow);
currencyComboBox = FormBuilder.addComboBox(formGridPane, "Currency used for bank account:", settings.getAllCurrencies(), ++gridRow); currencyComboBox = FormBuilder.addComboBox(formGridPane, "Currency used for bank account:", Utils.getAllCurrencies(), ++gridRow);
currencyComboBox.setPromptText("Select currency"); currencyComboBox.setPromptText("Select currency");
currencyComboBox.setConverter(new StringConverter<Currency>() currencyComboBox.setConverter(new StringConverter<Currency>()
{ {
@ -244,7 +241,7 @@ public class SetupController implements Initializable, ChildController, WalletFa
} }
}); });
countryComboBox = FormBuilder.addComboBox(formGridPane, "Country of bank account:", settings.getAllLocales(), ++gridRow); countryComboBox = FormBuilder.addComboBox(formGridPane, "Country of bank account:", Utils.getAllLocales(), ++gridRow);
countryComboBox.setPromptText("Select country"); countryComboBox.setPromptText("Select country");
countryComboBox.setConverter(new StringConverter<Locale>() countryComboBox.setConverter(new StringConverter<Locale>()
{ {
@ -270,6 +267,7 @@ public class SetupController implements Initializable, ChildController, WalletFa
skipButton.setText("Register later"); skipButton.setText("Register later");
// handlers // handlers
accountTitle.textProperty().addListener((ov, oldValue, newValue) -> checkCreateAccountButtonState());
accountHolderName.textProperty().addListener((ov, oldValue, newValue) -> checkCreateAccountButtonState()); accountHolderName.textProperty().addListener((ov, oldValue, newValue) -> checkCreateAccountButtonState());
accountPrimaryID.textProperty().addListener((ov, oldValue, newValue) -> checkCreateAccountButtonState()); accountPrimaryID.textProperty().addListener((ov, oldValue, newValue) -> checkCreateAccountButtonState());
accountSecondaryID.textProperty().addListener((ov, oldValue, newValue) -> checkCreateAccountButtonState()); accountSecondaryID.textProperty().addListener((ov, oldValue, newValue) -> checkCreateAccountButtonState());
@ -292,6 +290,8 @@ public class SetupController implements Initializable, ChildController, WalletFa
addBankAccountButton.setOnAction(e -> { addBankAccountButton.setOnAction(e -> {
addBankAccount(); addBankAccount();
storage.write(user.getClass().getName(), user);
if (verifyBankAccountData()) if (verifyBankAccountData())
{ {
bankTransferTypeComboBox.getSelectionModel().clearSelection(); bankTransferTypeComboBox.getSelectionModel().clearSelection();
@ -313,13 +313,15 @@ public class SetupController implements Initializable, ChildController, WalletFa
user.setAccountID(walletFacade.getAccountRegistrationAddress().toString()); user.setAccountID(walletFacade.getAccountRegistrationAddress().toString());
user.setMessageID(walletFacade.getAccountRegistrationPubKey().toString()); user.setMessageID(walletFacade.getAccountRegistrationPubKey().toString());
storage.saveUser(user); storage.write(user.getClass().getName(), user);
processStepBar.next(); processStepBar.next();
buildStep2(); buildStep2();
} catch (InsufficientMoneyException e1) } catch (InsufficientMoneyException e1)
{ {
log.warn(e1.toString()); log.warn(e1.toString());
// TODO
processStepBar.next();
buildStep2();
} }
} }
else else
@ -336,12 +338,14 @@ public class SetupController implements Initializable, ChildController, WalletFa
{ {
if (verifyBankAccountData()) if (verifyBankAccountData())
{ {
BankAccount bankAccount = new BankAccount((BankAccountType) bankTransferTypeComboBox.getSelectionModel().getSelectedItem(), BankAccount bankAccount = new BankAccount(
accountPrimaryID.getText(), (BankAccountType) bankTransferTypeComboBox.getSelectionModel().getSelectedItem(),
accountSecondaryID.getText(), (Currency) currencyComboBox.getSelectionModel().getSelectedItem(),
accountHolderName.getText(),
(Locale) countryComboBox.getSelectionModel().getSelectedItem(), (Locale) countryComboBox.getSelectionModel().getSelectedItem(),
(Currency) currencyComboBox.getSelectionModel().getSelectedItem()); accountTitle.getText(),
accountHolderName.getText(),
accountPrimaryID.getText(),
accountSecondaryID.getText());
user.addBankAccount(bankAccount); user.addBankAccount(bankAccount);
} }
} }
@ -360,20 +364,20 @@ public class SetupController implements Initializable, ChildController, WalletFa
formGridPane.getChildren().clear(); formGridPane.getChildren().clear();
int gridRow = -1; int gridRow = -1;
List<BankAccount> bankAccounts = user.getBankAccounts(); List<BankAccount> bankAccounts = user.getBankAccounts();
Iterator iterator = bankAccounts.iterator(); Iterator<BankAccount> iterator = bankAccounts.iterator();
int index = 0; int index = 0;
while (iterator.hasNext()) while (iterator.hasNext())
{ {
FormBuilder.addHeaderLabel(formGridPane, "Bank account " + (index + 1), ++gridRow); FormBuilder.addHeaderLabel(formGridPane, "Bank account " + (index + 1), ++gridRow);
Map.Entry<String, BankAccount> entry = (Map.Entry) iterator.next(); BankAccount bankAccount = iterator.next();
// need to get updated gridRow from subroutine // need to get updated gridRow from subroutine
gridRow = buildBankAccountDetails(entry.getValue(), ++gridRow); gridRow = buildBankAccountDetails(bankAccount, ++gridRow);
FormBuilder.addVSpacer(formGridPane, ++gridRow); FormBuilder.addVSpacer(formGridPane, ++gridRow);
index++; index++;
} }
FormBuilder.addVSpacer(formGridPane, ++gridRow); FormBuilder.addVSpacer(formGridPane, ++gridRow);
FormBuilder.addInputField(formGridPane, "Registration address:", walletFacade.getAccountRegistrationAddress().toString(), ++gridRow).setMouseTransparent(true); FormBuilder.addTextField(formGridPane, "Registration address:", walletFacade.getAccountRegistrationAddress().toString(), ++gridRow);
FormBuilder.addInputField(formGridPane, "Balance:", Formatter.formatSatoshis(walletFacade.getAccountRegistrationBalance(), true), ++gridRow).setMouseTransparent(true); FormBuilder.addTextField(formGridPane, "Balance:", Formatter.formatSatoshis(walletFacade.getAccountRegistrationBalance(), true), ++gridRow);
nextButton.setText("Done"); nextButton.setText("Done");
skipButton.setOpacity(0); skipButton.setOpacity(0);
@ -385,11 +389,13 @@ public class SetupController implements Initializable, ChildController, WalletFa
// util // util
private int buildBankAccountDetails(BankAccount bankAccount, int row) private int buildBankAccountDetails(BankAccount bankAccount, int row)
{ {
FormBuilder.addInputField(formGridPane, "Bank account holder name:", bankAccount.getAccountHolderName(), ++row).setMouseTransparent(true); FormBuilder.addTextField(formGridPane, "Bank account holder name:", bankAccount.getAccountHolderName(), ++row);
FormBuilder.addInputField(formGridPane, "Bank account type", bankAccount.getBankAccountType().toString(), ++row).setMouseTransparent(true); FormBuilder.addTextField(formGridPane, "Bank account type", bankAccount.getBankAccountType().toString(), ++row);
FormBuilder.addInputField(formGridPane, "Bank account primary ID", bankAccount.getAccountPrimaryID(), ++row).setMouseTransparent(true); FormBuilder.addTextField(formGridPane, "Bank account primary ID", bankAccount.getAccountPrimaryID(), ++row);
FormBuilder.addInputField(formGridPane, "Bank account secondary ID:", bankAccount.getAccountSecondaryID(), ++row).setMouseTransparent(true); FormBuilder.addTextField(formGridPane, "Bank account secondary ID:", bankAccount.getAccountSecondaryID(), ++row);
return row; return row;
} }
} }

View file

@ -4,7 +4,7 @@
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<AnchorPane fx:id="rootContainer" fx:controller="io.bitsquare.gui.setup.SetupController" <AnchorPane fx:id="rootContainer" fx:controller="io.bitsquare.gui.setup.SetupController"
xmlns:fx="http://javafx.com/fxml" minHeight="300" minWidth="400" prefHeight="600" prefWidth="800"> xmlns:fx="http://javafx.com/fxml">
<ScrollPane fitToWidth="true" AnchorPane.leftAnchor="10" AnchorPane.rightAnchor="10" AnchorPane.topAnchor="10" <ScrollPane fitToWidth="true" AnchorPane.leftAnchor="10" AnchorPane.rightAnchor="10" AnchorPane.topAnchor="10"
AnchorPane.bottomAnchor="30"> AnchorPane.bottomAnchor="30">
<content> <content>

View file

@ -84,5 +84,14 @@ public class TradeController implements Initializable, NavigationController, Chi
orderBookController.setDirection(direction); orderBookController.setDirection(direction);
} }
public void cleanup()
{
if (orderBookController != null)
{
orderBookController.cleanup();
orderBookController = null;
}
}
} }

View file

@ -1,77 +1,65 @@
package io.bitsquare.gui.trade.offer; package io.bitsquare.gui.trade.offer;
import com.google.bitcoin.core.InsufficientMoneyException;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bitsquare.btc.Fees;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.ChildController; import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.NavigationController; import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.util.Converter; import io.bitsquare.gui.components.ConfirmationComponent;
import io.bitsquare.gui.util.Formatter; import io.bitsquare.gui.util.*;
import io.bitsquare.settings.OrderBookFilterSettings;
import io.bitsquare.settings.Settings; import io.bitsquare.settings.Settings;
import io.bitsquare.trade.Direction; import io.bitsquare.trade.Direction;
import io.bitsquare.trade.Offer; import io.bitsquare.trade.Offer;
import io.bitsquare.trade.OfferConstraints;
import io.bitsquare.trade.Trading; import io.bitsquare.trade.Trading;
import io.bitsquare.trade.orderbook.OrderBook;
import io.bitsquare.trade.orderbook.OrderBookFilter; import io.bitsquare.trade.orderbook.OrderBookFilter;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.*; import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextField;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.GridPane;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.net.URL; import java.net.URL;
import java.util.ArrayList;
import java.util.Currency;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.UUID;
public class CreateOfferController implements Initializable, ChildController public class CreateOfferController implements Initializable, ChildController, WalletFacade.WalletListener
{ {
private static final Logger log = LoggerFactory.getLogger(CreateOfferController.class); private static final Logger log = LoggerFactory.getLogger(CreateOfferController.class);
private NavigationController navigationController; private NavigationController navigationController;
private Trading trading; private Trading trading;
private OrderBookFilterSettings orderBookFilterSettings; private WalletFacade walletFacade;
private Settings settings; private Settings settings;
private User user; private User user;
private double filterPaneItemOffset;
private Direction direction; private Direction direction;
@FXML private Button placeOfferButton;
public AnchorPane holderPane; private int gridRow;
@FXML
public Pane detailsPane;
@FXML
private AnchorPane holderPane;
@FXML
private GridPane formGridPane;
@FXML @FXML
public Label buyLabel; public Label buyLabel;
@FXML @FXML
public TextField volume; public TextField volume, amount, price, minAmount;
@FXML
public ImageView directionImageView;
@FXML
public TextField amount;
@FXML
public TextField price;
@FXML
public TextField minAmount;
@FXML
public Button placeOfferButton;
@Inject @Inject
public CreateOfferController(Trading trading, OrderBookFilterSettings orderBookFilterSettings, Settings settings, User user) public CreateOfferController(Trading trading, WalletFacade walletFacade, Settings settings, User user)
{ {
this.trading = trading; this.trading = trading;
this.orderBookFilterSettings = orderBookFilterSettings; this.walletFacade = walletFacade;
this.settings = settings; this.settings = settings;
this.user = user; this.user = user;
} }
@ -79,14 +67,34 @@ public class CreateOfferController implements Initializable, ChildController
@Override @Override
public void initialize(URL url, ResourceBundle rb) public void initialize(URL url, ResourceBundle rb)
{ {
createFilterPane(); walletFacade.addRegistrationWalletListener(this);
gridRow = 2;
FormBuilder.addVSpacer(formGridPane, ++gridRow);
FormBuilder.addHeaderLabel(formGridPane, "Offer details:", ++gridRow);
FormBuilder.addTextField(formGridPane, "Bank account type:", Localisation.get(user.getCurrentBankAccount().getBankAccountType().getType().toString()), ++gridRow);
FormBuilder.addTextField(formGridPane, "Bank account currency:", user.getCurrentBankAccount().getCurrency().getCurrencyCode(), ++gridRow);
FormBuilder.addTextField(formGridPane, "Bank account county:", user.getCurrentBankAccount().getCountryLocale().getDisplayCountry(), ++gridRow);
FormBuilder.addTextField(formGridPane, "Accepted countries:", Formatter.countryLocalesToString(settings.getAcceptedCountryLocales()), ++gridRow);
FormBuilder.addTextField(formGridPane, "Accepted languages:", Formatter.languageLocalesToString(settings.getAcceptedLanguageLocales()), ++gridRow);
FormBuilder.addVSpacer(formGridPane, ++gridRow);
Label placeOfferTitle = FormBuilder.addHeaderLabel(formGridPane, "Place offer:", ++gridRow);
TextField feeLabel = FormBuilder.addTextField(formGridPane, "Offer fee:", Formatter.formatSatoshis(Fees.OFFER_CREATION_FEE, true), ++gridRow);
feeLabel.setMouseTransparent(true);
placeOfferButton = new Button("Place offer");
formGridPane.add(placeOfferButton, 1, ++gridRow);
placeOfferButton.setDefaultButton(true);
// handlers
amount.textProperty().addListener(new ChangeListener<String>() amount.textProperty().addListener(new ChangeListener<String>()
{ {
@Override @Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
{ {
setVolume(); updateVolume();
} }
}); });
@ -95,23 +103,66 @@ public class CreateOfferController implements Initializable, ChildController
@Override @Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
{ {
setVolume(); updateVolume();
} }
}); });
placeOfferButton.setOnAction(e -> { placeOfferButton.setOnAction(e -> {
// TODO not impl yet. use mocks
OfferConstraints offerConstraints = new OrderBook(settings).getRandomOfferConstraints();
Offer offer = new Offer(UUID.randomUUID(),
direction,
Converter.convertToDouble(price.getText()),
Converter.convertToDouble(amount.getText()),
Converter.convertToDouble(minAmount.getText()),
settings.getCurrency(),
user,
offerConstraints);
trading.placeNewOffer(offer);
if (inputValid())
{
Offer offer = new Offer(user.getAccountID(),
user.getMessageID(),
direction,
Converter.stringToDouble(price.getText()),
Converter.stringToDouble(amount.getText()),
Converter.stringToDouble(minAmount.getText()),
user.getCurrentBankAccount().getBankAccountType().getType(),
user.getCurrentBankAccount().getCurrency(),
user.getCurrentBankAccount().getCountryLocale(),
settings.getAcceptedCountryLocales(),
settings.getAcceptedLanguageLocales());
try
{
String txID = trading.placeNewOffer(offer);
formGridPane.getChildren().remove(placeOfferButton);
placeOfferTitle.setText("Transaction sent:");
buildConfirmationView(txID);
} catch (InsufficientMoneyException e1)
{
//TODO popup
log.error(e.toString());
}
}
});
}
@Override
public void onConfidenceChanged(int numBroadcastPeers, int depthInBlocks)
{
log.info("onConfidenceChanged " + numBroadcastPeers + " / " + depthInBlocks);
}
@Override
public void onCoinsReceived(BigInteger newBalance)
{
log.info("onCoinsReceived " + newBalance);
}
private void buildConfirmationView(String txID)
{
FormBuilder.addTextField(formGridPane, "Transaction ID:", txID, ++gridRow, false, true);
ConfirmationComponent confirmationComponent = new ConfirmationComponent(walletFacade, formGridPane, ++gridRow);
Button closeButton = new Button("Close");
formGridPane.add(closeButton, 1, ++gridRow);
closeButton.setDefaultButton(true);
closeButton.setOnAction(e -> {
TabPane tabPane = ((TabPane) (holderPane.getParent().getParent())); TabPane tabPane = ((TabPane) (holderPane.getParent().getParent()));
tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem()); tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem());
@ -119,6 +170,7 @@ public class CreateOfferController implements Initializable, ChildController
}); });
} }
@Override @Override
public void setNavigationController(NavigationController navigationController) public void setNavigationController(NavigationController navigationController)
{ {
@ -132,140 +184,36 @@ public class CreateOfferController implements Initializable, ChildController
minAmount.setText(Formatter.formatPrice(orderBookFilter.getAmount())); minAmount.setText(Formatter.formatPrice(orderBookFilter.getAmount()));
price.setText(Formatter.formatPrice(orderBookFilter.getPrice())); price.setText(Formatter.formatPrice(orderBookFilter.getPrice()));
configDirection(); String iconPath = (direction == Direction.BUY) ? Icons.BUY : Icons.SELL;
buyLabel.setText(Formatter.formatDirection(direction, false) + ":");
updateVolume();
} }
private void configDirection() //TODO
private boolean inputValid()
{ {
String iconPath; return true;
String buyLabelText; }
if (direction == Direction.BUY)
{ private void updateVolume()
iconPath = "/images/buy.png"; {
buyLabelText = "BUY"; double amountAsDouble = Converter.stringToDouble(amount.getText());
} double priceAsDouble = Converter.stringToDouble(price.getText());
volume.setText(Formatter.formatPrice(amountAsDouble * priceAsDouble));
}
private Image getConfirmIconImage(int numBroadcastPeers, int depthInBlocks)
{
if (depthInBlocks > 0)
return Icons.getIconImage(Icons.getIconIDForConfirmations(depthInBlocks));
else else
{ return Icons.getIconImage(Icons.getIconIDForPeersSeenTx(numBroadcastPeers));
iconPath = "/images/sell.png";
buyLabelText = "SELL";
}
Image icon = new Image(getClass().getResourceAsStream(iconPath));
directionImageView.setImage(icon);
buyLabel.setText(buyLabelText);
} }
private void createFilterPane() private String getConfirmationsText(int registrationConfirmationNumBroadcastPeers, int registrationConfirmationDepthInBlocks)
{ {
filterPaneItemOffset = 30; return registrationConfirmationDepthInBlocks + " confirmation(s) / " + "Seen by " + registrationConfirmationNumBroadcastPeers + " peer(s)";
ArrayList<Currency> currencies = orderBookFilterSettings.getCurrencies();
Currency currency = orderBookFilterSettings.getCurrency();
ComboBox currencyComboBox = createCurrencyItem("Currency: ", currency, currencies);
currencyComboBox.valueProperty().addListener(new ChangeListener<Currency>()
{
@Override
public void changed(ObservableValue ov, Currency oldValue, Currency newValue)
{
orderBookFilterSettings.setCurrency(newValue);
}
});
Label bankLabel = createFilterItem("Bank transfer types: ", "SEPA, OKPAY");
Label countriesLabel = createFilterItem("Countries: ", "DE, GB, AT");
Label languagesLabel = createFilterItem("Languages: ", "DE, EN");
Label arbitratorsLabel = createFilterItem("Arbitrators: ", "Paysty, BitRated");
Label identityLabel = createFilterItem("Identity verifications: ", "Passport, Google+, Facebook, Skype");
TextField collateralLabel = createCollateralItem("Collateral (%): ", 10);
} }
private ComboBox createCurrencyItem(String labelText, Currency currency, ArrayList<Currency> currencies)
{
final Separator separator = new Separator();
separator.setPrefWidth(380);
separator.setLayoutY(0 + filterPaneItemOffset);
separator.setLayoutX(0);
final Label label = new Label(labelText);
label.setLayoutY(10 + filterPaneItemOffset);
ObservableList<Currency> options = FXCollections.observableArrayList(currencies);
final ComboBox comboBox = new ComboBox(options);
comboBox.setLayoutX(70);
comboBox.setLayoutY(5 + filterPaneItemOffset);
comboBox.setValue(currency);
detailsPane.getChildren().addAll(separator, label, comboBox);
filterPaneItemOffset += 40;
return comboBox;
}
private Label createFilterItem(String labelText, String valueText)
{
final Separator separator = new Separator();
separator.setPrefWidth(380);
separator.setLayoutY(0 + filterPaneItemOffset);
separator.setLayoutX(0);
final Label label = new Label(labelText + valueText);
label.setLayoutY(10 + filterPaneItemOffset);
label.setPrefWidth(310);
Tooltip tooltip = new Tooltip(valueText);
label.setTooltip(tooltip);
final Button edit = new Button("Edit");
edit.setPrefWidth(50);
edit.setLayoutX(330);
edit.setLayoutY(5 + filterPaneItemOffset);
detailsPane.getChildren().addAll(separator, label, edit);
filterPaneItemOffset += 40;
return label;
}
private TextField createCollateralItem(String labelText, double collateral)
{
final Separator separator = new Separator();
separator.setPrefWidth(380);
separator.setLayoutY(0 + filterPaneItemOffset);
separator.setLayoutX(0);
final Label label = new Label(labelText);
label.setLayoutY(10 + filterPaneItemOffset);
label.setPrefWidth(310);
final TextField collateralValue = new TextField(Double.toString(collateral));
collateralValue.setLayoutX(90);
collateralValue.setLayoutY(5 + filterPaneItemOffset);
collateralValue.setPrefWidth(50);
detailsPane.getChildren().addAll(separator, label, collateralValue);
filterPaneItemOffset += 40;
return collateralValue;
}
private double textInputToNumber(String oldValue, String newValue)
{
//TODO use regex.... or better custom textfield component
double d = 0.0;
if (!newValue.equals(""))
{
d = Converter.convertToDouble(newValue);
if (d == Double.NEGATIVE_INFINITY)
{
amount.setText(oldValue);
d = Converter.convertToDouble(oldValue);
}
}
return d;
}
private void setVolume()
{
double a = textInputToNumber(amount.getText(), amount.getText());
double p = textInputToNumber(price.getText(), price.getText());
volume.setText(Formatter.formatPrice(a * p));
}
} }

View file

@ -1,78 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<AnchorPane fx:id="holderPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" <AnchorPane fx:id="holderPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns:fx="http://javafx.com/fxml/1" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="io.bitsquare.gui.trade.offer.CreateOfferController"> fx:controller="io.bitsquare.gui.trade.offer.CreateOfferController">
<children> <children>
<HBox prefHeight="22.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0"> <VBox spacing="10" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="5.0"
<children> AnchorPane.bottomAnchor="10.0">
<ImageView fx:id="directionImageView"/> <GridPane fx:id="formGridPane" vgap="5" hgap="5">
<children>
<Label id="form-header-text" text="Create new offer:" GridPane.rowIndex="0"
GridPane.columnIndex="0"/>
<Label fx:id="buyLabel" text="Buy"> <Label fx:id="buyLabel" text="Buy" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
<padding>
<Insets left="4.0" right="4.0" top="5.0"/>
</padding>
</Label>
<TextField fx:id="amount" prefHeight="26.0" prefWidth="70.0" alignment="CENTER_RIGHT"> <HBox GridPane.rowIndex="1" GridPane.columnIndex="1" GridPane.hgrow="NEVER" spacing="5"
<HBox.margin> alignment="CENTER_RIGHT">
<Insets left="0.0"/> <children>
</HBox.margin> <TextField fx:id="amount" prefWidth="70.0" alignment="CENTER_RIGHT"/>
</TextField> <Label text="BTC for:"/>
<Label text="BTC for"> <TextField fx:id="price" prefWidth="70.0" alignment="CENTER_RIGHT"/>
<padding> <Label text="EUR ="/>
<Insets left="4.0" right="4.0" top="5.0"/> <TextField fx:id="volume" prefWidth="70.0" alignment="CENTER_RIGHT"
</padding> mouseTransparent="true"/>
</Label> <Label text="EUR in total"/>
<TextField fx:id="price" prefHeight="26.0" prefWidth="70.0" alignment="CENTER_RIGHT"/> </children>
<Label text="EUR ="> </HBox>
<padding>
<Insets left="4.0" right="4.0" top="5.0"/>
</padding>
</Label>
<TextField fx:id="volume" prefHeight="26.0" prefWidth="70.0" alignment="CENTER_RIGHT" editable="false"/>
<Label prefHeight="21.0" text="EUR in total (Min. Amount:">
<padding>
<Insets left="4.0" right="4.0" top="5.0"/>
</padding>
<HBox.margin>
<Insets/>
</HBox.margin>
</Label>
<TextField fx:id="minAmount" prefHeight="26.0" prefWidth="70.0" alignment="CENTER_RIGHT"/>
<Label text="BTC)">
<padding>
<Insets left="4.0" right="4.0" top="5.0"/>
</padding>
</Label>
</children> <Label text="Min. Amount:" GridPane.rowIndex="2" GridPane.columnIndex="0"/>
</HBox>
<Pane fx:id="detailsPane" AnchorPane.topAnchor="50.0" <TextField fx:id="minAmount" GridPane.rowIndex="2" GridPane.columnIndex="1"/>
AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0">
<Label text="Offer details:"> </children>
<font>
<Font size="18.0"/>
</font>
</Label>
</Pane>
<Label text="Place offer" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="380.0"> <padding>
<font> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
<Font size="18.0"/> </padding>
</font>
</Label>
<Separator AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="405.0"/>
<Label text="Offer fee: 0.01 BTC" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="415.0"/>
<Button fx:id="placeOfferButton" text="Place offer" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="440.0"/>
<columnConstraints>
<ColumnConstraints halignment="RIGHT"/>
<ColumnConstraints halignment="LEFT"/>
<ColumnConstraints halignment="LEFT"/>
</columnConstraints>
</GridPane>
</VBox>
</children> </children>
</AnchorPane> </AnchorPane>

View file

@ -10,14 +10,14 @@ import io.bitsquare.gui.util.Converter;
import io.bitsquare.gui.util.Formatter; import io.bitsquare.gui.util.Formatter;
import io.bitsquare.gui.util.Icons; import io.bitsquare.gui.util.Icons;
import io.bitsquare.gui.util.Localisation; import io.bitsquare.gui.util.Localisation;
import io.bitsquare.settings.Settings;
import io.bitsquare.trade.Direction; import io.bitsquare.trade.Direction;
import io.bitsquare.trade.orderbook.OrderBook; import io.bitsquare.trade.orderbook.OrderBook;
import io.bitsquare.trade.orderbook.OrderBookFilter; import io.bitsquare.trade.orderbook.OrderBookFilter;
import io.bitsquare.user.User;
import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList; import javafx.collections.transformation.SortedList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.geometry.Pos; import javafx.geometry.Pos;
@ -33,7 +33,6 @@ import org.slf4j.LoggerFactory;
import java.net.URL; import java.net.URL;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.ParseException; import java.text.ParseException;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -43,10 +42,11 @@ public class OrderBookController implements Initializable, ChildController
private NavigationController navigationController; private NavigationController navigationController;
private OrderBook orderBook; private OrderBook orderBook;
private OrderBookListItem selectedOrderBookListItem; private SortedList<OrderBookListItem> offerList;
private final OrderBookFilter orderBookFilter; private final OrderBookFilter orderBookFilter;
private User user;
private Button createOfferButton;
private Image buyIcon = Icons.getIconImage(Icons.BUY); private Image buyIcon = Icons.getIconImage(Icons.BUY);
private Image sellIcon = Icons.getIconImage(Icons.SELL); private Image sellIcon = Icons.getIconImage(Icons.SELL);
@ -61,22 +61,32 @@ public class OrderBookController implements Initializable, ChildController
@FXML @FXML
public TableColumn priceColumn, amountColumn, volumeColumn; public TableColumn priceColumn, amountColumn, volumeColumn;
@FXML @FXML
private TableColumn<OrderBookListItem, OrderBookListItem> directionColumn, countryColumn, bankAccountTypeColumn; private TableColumn<String, OrderBookListItem> directionColumn, countryColumn, bankAccountTypeColumn;
@FXML
public Button createOfferButton;
@Inject @Inject
public OrderBookController(OrderBook orderBook, OrderBookFilter orderBookFilter) public OrderBookController(OrderBook orderBook, OrderBookFilter orderBookFilter, User user)
{ {
this.orderBook = orderBook; this.orderBook = orderBook;
this.orderBookFilter = orderBookFilter; this.orderBookFilter = orderBookFilter;
this.user = user;
} }
@Override @Override
public void initialize(URL url, ResourceBundle rb) public void initialize(URL url, ResourceBundle rb)
{ {
// setup table
setCountryColumnCellFactory(); setCountryColumnCellFactory();
setBankAccountTypeColumnCellFactory(); setBankAccountTypeColumnCellFactory();
setDirectionColumnCellFactory(); setDirectionColumnCellFactory();
offerList = orderBook.getOfferList();
offerList.comparatorProperty().bind(orderBookTable.comparatorProperty());
orderBookTable.setItems(offerList);
orderBookTable.getSortOrder().add(priceColumn);
orderBookTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
// handlers
amount.textProperty().addListener(new ChangeListener<String>() amount.textProperty().addListener(new ChangeListener<String>()
{ {
@Override @Override
@ -97,10 +107,6 @@ public class OrderBookController implements Initializable, ChildController
} }
}); });
orderBookTable.getSelectionModel().selectedItemProperty().addListener((observableValue, oldValue, newValue) -> {
selectedOrderBookListItem = orderBookTable.getSelectionModel().getSelectedItem();
});
orderBookFilter.getChangedProperty().addListener(new ChangeListener<Boolean>() orderBookFilter.getChangedProperty().addListener(new ChangeListener<Boolean>()
{ {
@Override @Override
@ -109,8 +115,19 @@ public class OrderBookController implements Initializable, ChildController
updateOfferList(); updateOfferList();
} }
}); });
user.getChangedProperty().addListener(new ChangeListener<Boolean>()
{
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue)
{
updateOfferList();
}
});
updateOfferList(); createOfferButton.setOnAction(e -> {
ChildController nextController = navigationController.navigateToView(NavigationController.TRADE__CREATE_OFFER, "Create offer");
((CreateOfferController) nextController).setOrderBookFilter(orderBookFilter);
});
} }
@Override @Override
@ -126,6 +143,13 @@ public class OrderBookController implements Initializable, ChildController
orderBookFilter.setDirection(direction); orderBookFilter.setDirection(direction);
} }
public void cleanup()
{
orderBookTable.setItems(null);
orderBookTable.getSortOrder().clear();
offerList.comparatorProperty().unbind();
}
private void openTradeTab(OrderBookListItem orderBookListItem) private void openTradeTab(OrderBookListItem orderBookListItem)
{ {
String title = orderBookListItem.getOffer().getDirection() == Direction.BUY ? "Trade: Sell Bitcoin" : "Trade: Buy Bitcoin"; String title = orderBookListItem.getOffer().getDirection() == Direction.BUY ? "Trade: Sell Bitcoin" : "Trade: Buy Bitcoin";
@ -133,57 +157,31 @@ public class OrderBookController implements Initializable, ChildController
double requestedAmount = orderBookListItem.getOffer().getAmount(); double requestedAmount = orderBookListItem.getOffer().getAmount();
if (!amount.getText().equals("")) if (!amount.getText().equals(""))
requestedAmount = Converter.convertToDouble(amount.getText()); requestedAmount = Converter.stringToDouble(amount.getText());
tradeProcessController.initView(orderBookListItem.getOffer(), requestedAmount); tradeProcessController.initView(orderBookListItem.getOffer(), requestedAmount);
} }
private void displayCreateOfferButton()
{
if (createOfferButton == null)
{
createOfferButton = new Button("Create new offer");
holderPane.setBottomAnchor(createOfferButton, 360.0);
holderPane.setLeftAnchor(createOfferButton, 10.0);
holderPane.getChildren().add(createOfferButton);
createOfferButton.setOnAction(e -> {
ChildController nextController = navigationController.navigateToView(NavigationController.TRADE__CREATE_OFFER, "Create offer");
((CreateOfferController) nextController).setOrderBookFilter(orderBookFilter);
});
}
createOfferButton.setVisible(true);
holderPane.setBottomAnchor(orderBookTable, 390.0);
}
private void updateOfferList() private void updateOfferList()
{ {
ObservableList offers = orderBook.getFilteredList(orderBookFilter); orderBook.updateFilter(orderBookFilter);
orderBookTable.setItems(offers);
orderBookTable.getSortOrder().add(priceColumn);
priceColumn.setSortType((orderBookFilter.getDirection() == Direction.BUY) ? TableColumn.SortType.ASCENDING : TableColumn.SortType.DESCENDING);
if (offers.size() == 0) priceColumn.setSortType((orderBookFilter.getDirection() == Direction.BUY) ? TableColumn.SortType.ASCENDING : TableColumn.SortType.DESCENDING);
{ orderBookTable.sort();
displayCreateOfferButton();
} if (orderBookTable.getItems() != null)
else if (createOfferButton != null) createOfferButton.setDefaultButton(orderBookTable.getItems().size() == 0);
{
createOfferButton.setVisible(false);
holderPane.setBottomAnchor(orderBookTable, 10.0);
}
} }
private void setDirectionColumnCellFactory() private void setDirectionColumnCellFactory()
{ {
directionColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue())); directionColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue()));
directionColumn.setCellFactory(new Callback<TableColumn<OrderBookListItem, OrderBookListItem>, TableCell<OrderBookListItem, OrderBookListItem>>() directionColumn.setCellFactory(new Callback<TableColumn<String, OrderBookListItem>, TableCell<String, OrderBookListItem>>()
{ {
@Override @Override
public TableCell<OrderBookListItem, OrderBookListItem> call(TableColumn<OrderBookListItem, OrderBookListItem> directionColumn) public TableCell<String, OrderBookListItem> call(TableColumn<String, OrderBookListItem> directionColumn)
{ {
return new TableCell<OrderBookListItem, OrderBookListItem>() return new TableCell<String, OrderBookListItem>()
{ {
final ImageView iconView = new ImageView(); final ImageView iconView = new ImageView();
final Button button = new Button(); final Button button = new Button();
@ -216,6 +214,7 @@ public class OrderBookController implements Initializable, ChildController
button.setText(title); button.setText(title);
setGraphic(button); setGraphic(button);
button.setDefaultButton(getIndex() == 0);
button.setOnAction(event -> openTradeTab(orderBookListItem)); button.setOnAction(event -> openTradeTab(orderBookListItem));
} }
else else
@ -231,12 +230,12 @@ public class OrderBookController implements Initializable, ChildController
private void setCountryColumnCellFactory() private void setCountryColumnCellFactory()
{ {
countryColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue())); countryColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue()));
countryColumn.setCellFactory(new Callback<TableColumn<OrderBookListItem, OrderBookListItem>, TableCell<OrderBookListItem, OrderBookListItem>>() countryColumn.setCellFactory(new Callback<TableColumn<String, OrderBookListItem>, TableCell<String, OrderBookListItem>>()
{ {
@Override @Override
public TableCell<OrderBookListItem, OrderBookListItem> call(TableColumn<OrderBookListItem, OrderBookListItem> directionColumn) public TableCell<String, OrderBookListItem> call(TableColumn<String, OrderBookListItem> directionColumn)
{ {
return new TableCell<OrderBookListItem, OrderBookListItem>() return new TableCell<String, OrderBookListItem>()
{ {
final HBox hBox = new HBox(); final HBox hBox = new HBox();
@ -251,44 +250,19 @@ public class OrderBookController implements Initializable, ChildController
{ {
super.updateItem(orderBookListItem, empty); super.updateItem(orderBookListItem, empty);
hBox.getChildren().clear();
if (orderBookListItem != null) if (orderBookListItem != null)
{ {
hBox.getChildren().clear(); Locale countryLocale = orderBookListItem.getOffer().getBankAccountCountryLocale();
setText(""); try
List<Locale> countryLocales = orderBookListItem.getOffer().getOfferConstraints().getCountryLocales();
int i = 0;
String countries = "";
for (Locale countryLocale : countryLocales)
{ {
countries += countryLocale.getDisplayCountry(); hBox.getChildren().add(Icons.getIconImageView("/images/countries/" + countryLocale.getCountry().toLowerCase() + ".png"));
if (i < countryLocales.size() - 1)
countries += ", ";
if (i < 4) } catch (Exception e)
{ {
try log.warn("Country icon not found: " + "/images/countries/" + countryLocale.getCountry().toLowerCase() + ".png country name: " + countryLocale.getDisplayCountry());
{
ImageView imageView = Icons.getIconImageView("/images/countries/" + countryLocale.getCountry().toLowerCase() + ".png");
hBox.getChildren().add(imageView);
} catch (Exception e)
{
log.warn("Country icon not found: " + "/images/countries/" + countryLocale.getCountry().toLowerCase() + ".png country name: " + countryLocale.getDisplayCountry());
}
}
else
{
setText("...");
}
i++;
} }
Tooltip.install(this, new Tooltip(countries)); Tooltip.install(this, new Tooltip(countryLocale.getDisplayCountry()));
}
else
{
setText("");
hBox.getChildren().clear();
} }
} }
}; };
@ -299,12 +273,12 @@ public class OrderBookController implements Initializable, ChildController
private void setBankAccountTypeColumnCellFactory() private void setBankAccountTypeColumnCellFactory()
{ {
bankAccountTypeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue())); bankAccountTypeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue()));
bankAccountTypeColumn.setCellFactory(new Callback<TableColumn<OrderBookListItem, OrderBookListItem>, TableCell<OrderBookListItem, OrderBookListItem>>() bankAccountTypeColumn.setCellFactory(new Callback<TableColumn<String, OrderBookListItem>, TableCell<String, OrderBookListItem>>()
{ {
@Override @Override
public TableCell<OrderBookListItem, OrderBookListItem> call(TableColumn<OrderBookListItem, OrderBookListItem> directionColumn) public TableCell<String, OrderBookListItem> call(TableColumn<String, OrderBookListItem> directionColumn)
{ {
return new TableCell<OrderBookListItem, OrderBookListItem>() return new TableCell<String, OrderBookListItem>()
{ {
@Override @Override
public void updateItem(final OrderBookListItem orderBookListItem, boolean empty) public void updateItem(final OrderBookListItem orderBookListItem, boolean empty)
@ -313,19 +287,8 @@ public class OrderBookController implements Initializable, ChildController
if (orderBookListItem != null) if (orderBookListItem != null)
{ {
List<BankAccountType.BankAccountTypeEnum> bankAccountTypeEnums = orderBookListItem.getOffer().getOfferConstraints().getBankAccountTypes(); BankAccountType.BankAccountTypeEnum bankAccountTypeEnum = orderBookListItem.getOffer().getBankAccountTypeEnum();
String text = ""; setText(Localisation.get(bankAccountTypeEnum.toString()));
int i = 0;
for (BankAccountType.BankAccountTypeEnum bankAccountTypeEnum : bankAccountTypeEnums)
{
text += Localisation.get(bankAccountTypeEnum.toString());
i++;
if (i < bankAccountTypeEnums.size())
text += ", ";
}
setText(text);
if (text.length() > 20)
Tooltip.install(this, new Tooltip(text));
} }
else else
{ {
@ -345,12 +308,12 @@ public class OrderBookController implements Initializable, ChildController
{ {
try try
{ {
DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Settings.getLocale()); DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Locale.getDefault());
d = decimalFormat.parse(newValue).doubleValue(); d = decimalFormat.parse(newValue).doubleValue();
} catch (ParseException e) } catch (ParseException e)
{ {
amount.setText(oldValue); amount.setText(oldValue);
d = Converter.convertToDouble(oldValue); d = Converter.stringToDouble(oldValue);
} }
} }
return d; return d;
@ -363,5 +326,23 @@ public class OrderBookController implements Initializable, ChildController
volume.setText(Formatter.formatPrice(a * p)); volume.setText(Formatter.formatPrice(a * p));
} }
// the scrollbar width is not handled correctly from the layout initially
/* private void forceTableLayoutUpdate()
{
final List<OrderBookListItem> items = orderBookTable.getItems();
if (items == null || items.size() == 0) return;
final OrderBookListItem item = orderBookTable.getItems().get(0);
items.remove(0);
Platform.runLater(new Runnable()
{
@Override
public void run()
{
items.add(0, item);
}
});
} */
} }

View file

@ -1,134 +0,0 @@
package io.bitsquare.gui.trade.orderbook;
import io.bitsquare.gui.components.VSpacer;
import io.bitsquare.gui.util.Icons;
import io.bitsquare.settings.Settings;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Pane;
import java.util.*;
public class OrderBookFilterTextItemBuilder
{
public static void build(Pane parent, String title, List<String> values, List<String> allValues)
{
final Pane pane = new Pane();
pane.setPrefHeight(23);
final Label titleLabel = new Label(title);
titleLabel.setLayoutY(4);
titleLabel.setId("form-title");
FlowPane flowPane = new FlowPane();
double xPos = 170.0;
double yPos = 5.0;
List<String> openValues = new ArrayList<>(allValues);
openValues.removeAll(values);
ObservableList<String> observableList = FXCollections.observableArrayList(openValues);
Collections.sort(observableList);
ComboBox comboBox = new ComboBox(observableList);
comboBox.setLayoutX(xPos);
comboBox.setLayoutY(yPos);
comboBox.setClip(Icons.getIconImageView(Icons.ADD));
comboBox.setValue(Settings.getCurrency());
comboBox.valueProperty().addListener(new ChangeListener<Object>()
{
@Override
public void changed(ObservableValue ov, Object oldValue, Object newValue)
{
if (newValue != null)
{
String value;
if (newValue instanceof Currency)
value = ((Currency) newValue).getCurrencyCode();
else
value = (String) newValue;
if (flowPane.getChildren().size() > 0)
{
Pane lastItem = (Pane) flowPane.getChildren().get(flowPane.getChildren().size() - 1);
Button button = (Button) lastItem.getChildren().get(0);
button.setText(button.getText().substring(0, button.getText().length() - 2) + ", ");
}
addRemovableItem(flowPane, value + " ", observableList);
comboBox.getSelectionModel().clearSelection();
observableList.remove(newValue);
}
}
});
// combobox does not support icon (mask background with icon), so we need a graphic here
ImageView addImageView = Icons.getIconImageView(Icons.ADD);
addImageView.setLayoutX(xPos);
addImageView.setLayoutY(yPos);
addImageView.setMouseTransparent(true);
pane.getChildren().addAll(titleLabel, comboBox, addImageView);
Iterator<String> iterator = values.iterator();
for (Iterator<String> stringIterator = iterator; stringIterator.hasNext(); )
{
String value = stringIterator.next();
if (stringIterator.hasNext())
addRemovableItem(flowPane, value + ", ", observableList);
else
addRemovableItem(flowPane, value + " ", observableList);
}
parent.getChildren().addAll(pane, flowPane, new VSpacer(3), new Separator(), new VSpacer(10));
}
private static void addRemovableItem(FlowPane flowPane, String text, ObservableList<String> observableList)
{
Pane pane = new Pane();
Button icon = new Button("", Icons.getIconImageView(Icons.REMOVE));
icon.setStyle("-fx-background-color: transparent;");
icon.setPadding(new Insets(-5.0, 0.0, 0.0, 0.0));
icon.setVisible(false);
Button button = new Button(text);
button.setStyle("-fx-background-color: transparent;");
button.setPadding(new Insets(0.0, 0.0, 0.0, 0.0));
pane.setOnMouseEntered(e -> {
icon.setVisible(true);
icon.setLayoutX(button.getWidth() - 7);
});
pane.setOnMouseExited(e -> {
icon.setVisible(false);
icon.setLayoutX(0);
});
icon.setOnAction(e -> {
flowPane.getChildren().remove(button.getParent());
observableList.add(text);
Collections.sort(observableList);
if (flowPane.getChildren().size() > 0)
{
Pane lastItem = (Pane) flowPane.getChildren().get(flowPane.getChildren().size() - 1);
Button lastButton = (Button) lastItem.getChildren().get(0);
lastButton.setText(lastButton.getText().substring(0, lastButton.getText().length() - 2) + " ");
}
});
pane.getChildren().addAll(button, icon);
flowPane.getChildren().add(pane);
}
}

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?> <?import javafx.geometry.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<AnchorPane fx:id="holderPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" <AnchorPane fx:id="holderPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns:fx="http://javafx.com/fxml/1" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns:fx="http://javafx.com/fxml/1"
@ -40,27 +40,31 @@
</children> </children>
</HBox> </HBox>
<Button fx:id="createOfferButton" text="Create new offer" AnchorPane.topAnchor="10.0"
AnchorPane.rightAnchor="10.0"/>
<TableView fx:id="orderBookTable" id="orderbook-table" AnchorPane.leftAnchor="10.0" <TableView fx:id="orderBookTable" id="orderbook-table" AnchorPane.leftAnchor="10.0"
AnchorPane.topAnchor="40.0" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="10.0"> AnchorPane.topAnchor="45.0" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="10.0">
<columns> <columns>
<TableColumn text="Amount (Min.)" fx:id="amountColumn" prefWidth="120"> <TableColumn text="Amount (Min.)" fx:id="amountColumn" minWidth="120">
<cellValueFactory> <cellValueFactory>
<PropertyValueFactory property="amount"/> <PropertyValueFactory property="amount"/>
</cellValueFactory> </cellValueFactory>
</TableColumn> </TableColumn>
<TableColumn text="Price" fx:id="priceColumn" prefWidth="100"> <TableColumn text="Price" fx:id="priceColumn" minWidth="70">
<cellValueFactory> <cellValueFactory>
<PropertyValueFactory property="price"/> <PropertyValueFactory property="price"/>
</cellValueFactory> </cellValueFactory>
</TableColumn> </TableColumn>
<TableColumn text="Volume (Min.)" fx:id="volumeColumn" prefWidth="160"> <TableColumn text="Volume (Min.)" fx:id="volumeColumn" minWidth="130">
<cellValueFactory> <cellValueFactory>
<PropertyValueFactory property="volume"/> <PropertyValueFactory property="volume"/>
</cellValueFactory> </cellValueFactory>
</TableColumn> </TableColumn>
<TableColumn text="Country" fx:id="countryColumn" prefWidth="100" sortable="false"/> <TableColumn text="Country" fx:id="countryColumn" minWidth="60"/>
<TableColumn text="Bank transfer type" fx:id="bankAccountTypeColumn" prefWidth="180"/> <TableColumn text="Bank transfer type" fx:id="bankAccountTypeColumn" minWidth="140"/>
<TableColumn text="" fx:id="directionColumn" prefWidth="100" sortable="false"/> <TableColumn text="" fx:id="directionColumn" minWidth="80" sortable="false"/>
</columns> </columns>
</TableView> </TableView>

View file

@ -45,7 +45,7 @@ public class TradeProcessController implements Initializable, ChildController
private TextField amountTextField; private TextField amountTextField;
private Label offererPubKeyLabel, offererAccountPrimaryID, offererAccountSecondaryIDLabel, private Label offererPubKeyLabel, offererAccountPrimaryID, offererAccountSecondaryIDLabel,
offererAccountHolderNameLabel, feedbackLabel, infoLabel, totalLabel, volumeLabel, totalToPayLabel, offererAccountHolderNameLabel, feedbackLabel, infoLabel, totalLabel, volumeLabel, totalToPayLabel,
totalToReceiveLabel, collateralLabel1, collateralLabel2, amountLabel; /*totalToReceiveLabel,*/ amountLabel;
private Pane progressPane; private Pane progressPane;
private ProgressBar progressBar; private ProgressBar progressBar;
private ProgressIndicator progressIndicator; private ProgressIndicator progressIndicator;
@ -90,7 +90,7 @@ public class TradeProcessController implements Initializable, ChildController
private void trade() private void trade()
{ {
double requestedAmount = Converter.convertToDouble(amountTextField.getText()); double requestedAmount = Converter.stringToDouble(amountTextField.getText());
if (requestedAmount <= offer.getAmount() && requestedAmount >= offer.getMinAmount()) if (requestedAmount <= offer.getAmount() && requestedAmount >= offer.getMinAmount())
{ {
amountTextField.setEditable(false); amountTextField.setEditable(false);
@ -137,7 +137,7 @@ public class TradeProcessController implements Initializable, ChildController
{ {
trading.sendTakeOfferRequest(trade); trading.sendTakeOfferRequest(trade);
feedbackLabel.setText("Request take offer confirmation from peer."); feedbackLabel.setText("Request take offer confirmation from peer.");
Utils.setTimeout(500, (AnimationTimer animationTimer) -> { GUIUtils.setTimeout(500, (AnimationTimer animationTimer) -> {
onTakeOfferRequestConfirmed(); onTakeOfferRequestConfirmed();
progressBar.setProgress(1.0 / 3.0); progressBar.setProgress(1.0 / 3.0);
return null; return null;
@ -149,7 +149,7 @@ public class TradeProcessController implements Initializable, ChildController
trading.payOfferFee(trade); trading.payOfferFee(trade);
feedbackLabel.setText("Request offer fee payment confirmation from peer."); feedbackLabel.setText("Request offer fee payment confirmation from peer.");
Utils.setTimeout(500, (AnimationTimer animationTimer) -> { GUIUtils.setTimeout(500, (AnimationTimer animationTimer) -> {
onOfferFeePaymentConfirmed(); onOfferFeePaymentConfirmed();
progressBar.setProgress(2.0 / 3.0); progressBar.setProgress(2.0 / 3.0);
return null; return null;
@ -160,7 +160,7 @@ public class TradeProcessController implements Initializable, ChildController
{ {
trading.requestOffererDetailData(); trading.requestOffererDetailData();
feedbackLabel.setText("Request detail data from peer."); feedbackLabel.setText("Request detail data from peer.");
Utils.setTimeout(500, (AnimationTimer animationTimer) -> { GUIUtils.setTimeout(500, (AnimationTimer animationTimer) -> {
onUserDetailsReceived(); onUserDetailsReceived();
progressBar.setProgress(1.0); progressBar.setProgress(1.0);
return null; return null;
@ -187,7 +187,7 @@ public class TradeProcessController implements Initializable, ChildController
infoLabel = new Label("Wait for Bank transfer."); infoLabel = new Label("Wait for Bank transfer.");
vBox.getChildren().addAll(infoLabel); vBox.getChildren().addAll(infoLabel);
Utils.setTimeout(2000, (AnimationTimer animationTimer) -> { GUIUtils.setTimeout(2000, (AnimationTimer animationTimer) -> {
onBankTransferInited(); onBankTransferInited();
return null; return null;
}); });
@ -218,7 +218,7 @@ public class TradeProcessController implements Initializable, ChildController
summaryGridPane.setPadding(new Insets(5, 5, 5, 5)); summaryGridPane.setPadding(new Insets(5, 5, 5, 5));
FormBuilder.addLabel(summaryGridPane, "You have payed:", getTotalToPay(), ++row); FormBuilder.addLabel(summaryGridPane, "You have payed:", getTotalToPay(), ++row);
FormBuilder.addLabel(summaryGridPane, "You have received:\n ", getTotalToReceive(), ++row); // FormBuilder.addLabel(summaryGridPane, "You have received:\n ", getTotalToReceive(), ++row);
TitledPane summaryTitlePane = new TitledPane("Trade summary:", summaryGridPane); TitledPane summaryTitlePane = new TitledPane("Trade summary:", summaryGridPane);
summaryTitlePane.setCollapsible(false); summaryTitlePane.setCollapsible(false);
@ -235,7 +235,6 @@ public class TradeProcessController implements Initializable, ChildController
private void buildStep1() private void buildStep1()
{ {
OfferConstraints offerConstraints = offer.getOfferConstraints();
User taker = contract.getTaker(); User taker = contract.getTaker();
User offerer = contract.getOfferer(); User offerer = contract.getOfferer();
@ -245,13 +244,13 @@ public class TradeProcessController implements Initializable, ChildController
offerDetailsGridPane.setHgap(5); offerDetailsGridPane.setHgap(5);
offerDetailsGridPane.setPadding(new Insets(5, 5, 5, 5)); offerDetailsGridPane.setPadding(new Insets(5, 5, 5, 5));
amountTextField = FormBuilder.addInputField(offerDetailsGridPane, "Amount (BTC):", Formatter.formatAmount(getAmount()), ++row); amountTextField = FormBuilder.addTextField(offerDetailsGridPane, "Amount (BTC):", Formatter.formatAmount(getAmount()), ++row);
amountTextField.textProperty().addListener(e -> { amountTextField.textProperty().addListener(e -> {
setTotal(); setTotal();
setVolume(); setVolume();
setCollateral(); //setCollateral();
totalToPayLabel.setText(getTotalToPay()); totalToPayLabel.setText(getTotalToPay());
totalToReceiveLabel.setText(getTotalToReceive()); // totalToReceiveLabel.setText(getTotalToReceive());
amountLabel.setText(amountTextField.getText()); amountLabel.setText(amountTextField.getText());
}); });
@ -261,11 +260,10 @@ public class TradeProcessController implements Initializable, ChildController
FormBuilder.addLabel(offerDetailsGridPane, "Price:", Formatter.formatPriceWithCurrencyPair(offer.getPrice(), offer.getCurrency()), ++row); FormBuilder.addLabel(offerDetailsGridPane, "Price:", Formatter.formatPriceWithCurrencyPair(offer.getPrice(), offer.getCurrency()), ++row);
totalLabel = FormBuilder.addLabel(offerDetailsGridPane, "Total:", "", ++row); totalLabel = FormBuilder.addLabel(offerDetailsGridPane, "Total:", "", ++row);
setTotal(); setTotal();
collateralLabel1 = FormBuilder.addLabel(offerDetailsGridPane, "Collateral:", Formatter.formatCollateral(offer.getOfferConstraints().getCollateral(), getAmount()), ++row);
FormBuilder.addLabel(offerDetailsGridPane, "Offer fee:", Formatter.formatSatoshis(Fees.OFFER_CREATION_FEE, true), ++row); FormBuilder.addLabel(offerDetailsGridPane, "Offer fee:", Formatter.formatSatoshis(Fees.OFFER_CREATION_FEE, true), ++row);
FormBuilder.addVSpacer(offerDetailsGridPane, ++row); FormBuilder.addVSpacer(offerDetailsGridPane, ++row);
totalToPayLabel = FormBuilder.addLabel(offerDetailsGridPane, "You pay:", getTotalToPay(), ++row); totalToPayLabel = FormBuilder.addLabel(offerDetailsGridPane, "You pay:", getTotalToPay(), ++row);
totalToReceiveLabel = FormBuilder.addLabel(offerDetailsGridPane, "You receive:\n ", getTotalToReceive(), ++row); // totalToReceiveLabel = FormBuilder.addLabel(offerDetailsGridPane, "You receive:\n ", getTotalToReceive(), ++row);
offerDetailsTitlePane = new TitledPane(takerIsSelling() ? "Sell Bitcoin" : "Buy Bitcoin", offerDetailsGridPane); offerDetailsTitlePane = new TitledPane(takerIsSelling() ? "Sell Bitcoin" : "Buy Bitcoin", offerDetailsGridPane);
offerDetailsTitlePane.setCollapsible(false); offerDetailsTitlePane.setCollapsible(false);
@ -286,10 +284,9 @@ public class TradeProcessController implements Initializable, ChildController
volumeLabel = FormBuilder.addLabel(contractGridPane, "Volume:", "", ++row); volumeLabel = FormBuilder.addLabel(contractGridPane, "Volume:", "", ++row);
setVolume(); setVolume();
FormBuilder.addLabel(contractGridPane, "Price:", Formatter.formatPriceWithCurrencyPair(offer.getPrice(), offer.getCurrency()), ++row); FormBuilder.addLabel(contractGridPane, "Price:", Formatter.formatPriceWithCurrencyPair(offer.getPrice(), offer.getCurrency()), ++row);
collateralLabel2 = FormBuilder.addLabel(contractGridPane, "Collateral:", "", ++row); //setCollateral();
setCollateral(); // FormBuilder.addLabel(contractGridPane, "Language:", Formatter.formatList(offerConstraints.getAcceptedLanguageLocales()), ++row);
// FormBuilder.addLabel(contractGridPane, "Language:", Formatter.formatList(offerConstraints.getLanguageLocales()), ++row); // FormBuilder.addLabel(contractGridPane, "Arbitrator:", offerConstraints.getArbitrator(), ++row);
FormBuilder.addLabel(contractGridPane, "Arbitrator:", offerConstraints.getArbitrator(), ++row);
// FormBuilder.addLabel(contractGridPane, "Identity verification:", Formatter.formatList(offerConstraints.getIdentityVerifications()), ++row); // FormBuilder.addLabel(contractGridPane, "Identity verification:", Formatter.formatList(offerConstraints.getIdentityVerifications()), ++row);
FormBuilder.addLabel(contractGridPane, "Bank transfer reference ID:", "Purchase xyz 01.04.2014", ++row); FormBuilder.addLabel(contractGridPane, "Bank transfer reference ID:", "Purchase xyz 01.04.2014", ++row);
@ -299,8 +296,8 @@ public class TradeProcessController implements Initializable, ChildController
FormBuilder.addLabel(contractGridPane, "Messaging ID:", offerer.getMessageID(), ++row); FormBuilder.addLabel(contractGridPane, "Messaging ID:", offerer.getMessageID(), ++row);
//FormBuilder.addLabel(contractGridPane, "Country:", offerer.getCountry(), ++row); //FormBuilder.addLabel(contractGridPane, "Country:", offerer.getCountry(), ++row);
offererPubKeyLabel = FormBuilder.addLabel(contractGridPane, "Payment public key:", contract.getOffererPubKey(), ++row); offererPubKeyLabel = FormBuilder.addLabel(contractGridPane, "Payment public key:", contract.getOffererPubKey(), ++row);
FormBuilder.addLabel(contractGridPane, "Bank transfer type:", offerer.getCurrentBankAccount().getBankAccountType().toString(), ++row); // FormBuilder.addLabel(contractGridPane, "Bank transfer type:", offerer.getCurrentBankAccount().getBankAccountType().toString(), ++row);
offererAccountPrimaryID = FormBuilder.addLabel(contractGridPane, "Bank account IBAN:", offerer.getCurrentBankAccount().getAccountPrimaryID(), ++row); // offererAccountPrimaryID = FormBuilder.addLabel(contractGridPane, "Bank account IBAN:", offerer.getCurrentBankAccount().getAccountPrimaryID(), ++row);
offererAccountSecondaryIDLabel = FormBuilder.addLabel(contractGridPane, "Bank account BIC:", offerer.getCurrentBankAccount().getAccountSecondaryID(), ++row); offererAccountSecondaryIDLabel = FormBuilder.addLabel(contractGridPane, "Bank account BIC:", offerer.getCurrentBankAccount().getAccountSecondaryID(), ++row);
offererAccountHolderNameLabel = FormBuilder.addLabel(contractGridPane, "Bank account holder:", offerer.getCurrentBankAccount().getAccountHolderName(), ++row); offererAccountHolderNameLabel = FormBuilder.addLabel(contractGridPane, "Bank account holder:", offerer.getCurrentBankAccount().getAccountHolderName(), ++row);
@ -352,7 +349,7 @@ public class TradeProcessController implements Initializable, ChildController
private double getVolume() private double getVolume()
{ {
return offer.getPrice() * Converter.convertToDouble(amountTextField.getText()); return offer.getPrice() * Converter.stringToDouble(amountTextField.getText());
} }
private double getAmount() private double getAmount()
@ -365,40 +362,40 @@ public class TradeProcessController implements Initializable, ChildController
String result = ""; String result = "";
if (takerIsSelling()) if (takerIsSelling())
{ {
double btcValue = Converter.convertToDouble(amountTextField.getText()) + BtcFormatter.satoshiToBTC(Fees.OFFER_CREATION_FEE) + double btcValue = Converter.stringToDouble(amountTextField.getText()) + BtcFormatter.satoshiToBTC(Fees.OFFER_CREATION_FEE)/* +
offer.getOfferConstraints().getCollateral() * Converter.convertToDouble(amountTextField.getText()); offer.getConstraints().getCollateral() * Converter.stringToDouble(amountTextField.getText())*/;
result = Formatter.formatAmount(btcValue, true, true); result = Formatter.formatAmount(btcValue, true, true);
} }
else else
{ {
double btcValue = BtcFormatter.satoshiToBTC(Fees.OFFER_CREATION_FEE) + offer.getOfferConstraints().getCollateral() * Converter.convertToDouble(amountTextField.getText()); double btcValue = BtcFormatter.satoshiToBTC(Fees.OFFER_CREATION_FEE) /*+ offer.getConstraints().getCollateral() * Converter.stringToDouble(amountTextField.getText())*/;
result = Formatter.formatAmount(btcValue, true, true) + "\n" + Formatter.formatVolume(getVolume(), offer.getCurrency()); result = Formatter.formatAmount(btcValue, true, true) + "\n" + Formatter.formatVolume(getVolume(), offer.getCurrency());
} }
return result; return result;
} }
private String getTotalToReceive() /*private String getTotalToReceive()
{ {
String result = ""; String result = "";
if (takerIsSelling()) if (takerIsSelling())
{ {
double btcValue = offer.getOfferConstraints().getCollateral() * Converter.convertToDouble(amountTextField.getText()); double btcValue = offer.getConstraints().getCollateral() * Converter.stringToDouble(amountTextField.getText());
result = Formatter.formatAmount(btcValue, true, true) + "\n" + Formatter.formatVolume(getVolume(), offer.getCurrency()); result = Formatter.formatAmount(btcValue, true, true) + "\n" + Formatter.formatVolume(getVolume(), offer.getCurrency());
} }
else else
{ {
double btcValue = Converter.convertToDouble(amountTextField.getText()) + double btcValue = Converter.stringToDouble(amountTextField.getText()) +
offer.getOfferConstraints().getCollateral() * Converter.convertToDouble(amountTextField.getText()); offer.getConstraints().getCollateral() * Converter.stringToDouble(amountTextField.getText());
result = Formatter.formatAmount(btcValue, true, true); result = Formatter.formatAmount(btcValue, true, true);
} }
return result; return result;
} } */
public void setCollateral() /*public void setCollateral()
{ {
String value = Formatter.formatCollateral(offer.getOfferConstraints().getCollateral(), Converter.convertToDouble(amountTextField.getText())); String value = Formatter.formatCollateral(offer.getConstraints().getCollateral(), Converter.stringToDouble(amountTextField.getText()));
collateralLabel1.setText(value); collateralLabel1.setText(value);
collateralLabel2.setText(value); collateralLabel2.setText(value);
} }*/
} }

View file

@ -1,23 +1,27 @@
package io.bitsquare.gui.util; package io.bitsquare.gui.util;
import io.bitsquare.settings.Settings; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.ParseException; import java.text.ParseException;
import java.util.Locale;
public class Converter public class Converter
{ {
public static double convertToDouble(String input) private static final Logger log = LoggerFactory.getLogger(Converter.class);
public static double stringToDouble(String input)
{ {
try try
{ {
DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Settings.getLocale()); DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Locale.getDefault());
return decimalFormat.parse(input).doubleValue(); return decimalFormat.parse(input).doubleValue();
} catch (ParseException e) } catch (ParseException e)
{ {
//e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. log.warn(e.toString());
} }
return 0.0; return 0;
} }

View file

@ -1,11 +1,11 @@
package io.bitsquare.gui.util; package io.bitsquare.gui.util;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.components.VSpacer; import io.bitsquare.gui.components.VSpacer;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.scene.control.Button; import javafx.scene.control.*;
import javafx.scene.control.ComboBox; import javafx.scene.image.Image;
import javafx.scene.control.Label; import javafx.scene.image.ImageView;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import java.util.List; import java.util.List;
@ -20,18 +20,32 @@ public class FormBuilder
return valueLabel; return valueLabel;
} }
public static void addHeaderLabel(GridPane gridPane, String title, int row) public static Label addHeaderLabel(GridPane gridPane, String title, int row)
{ {
Label headerLabel = new Label(title); Label headerLabel = new Label(title);
headerLabel.setId("form-header-text"); headerLabel.setId("form-header-text");
gridPane.add(headerLabel, 0, row); gridPane.add(headerLabel, 0, row);
return headerLabel;
} }
public static TextField addInputField(GridPane gridPane, String title, String value, int row) public static TextField addInputField(GridPane gridPane, String title, String value, int row)
{
return addTextField(gridPane, title, value, row, true, true);
}
public static TextField addTextField(GridPane gridPane, String title, String value, int row)
{
return addTextField(gridPane, title, value, row, false, false);
}
public static TextField addTextField(GridPane gridPane, String title, String value, int row, boolean editable, boolean selectable)
{ {
gridPane.add(new Label(title), 0, row); gridPane.add(new Label(title), 0, row);
TextField textField = new TextField(value); TextField textField = new TextField(value);
gridPane.add(textField, 1, row); gridPane.add(textField, 1, row);
textField.setMouseTransparent(!selectable && !editable);
textField.setEditable(editable);
return textField; return textField;
} }
@ -54,4 +68,49 @@ public class FormBuilder
gridPane.add(comboBox, 1, row); gridPane.add(comboBox, 1, row);
return comboBox; return comboBox;
} }
public static TextField addConfirmationsLabel(GridPane gridPane, WalletFacade walletFacade, int row)
{
return FormBuilder.addTextField(gridPane, "Confirmations:", getConfirmationText(walletFacade), row);
}
public static ProgressIndicator addConfirmationsSpinner(GridPane gridPane, WalletFacade walletFacade, int row)
{
ProgressIndicator progressIndicator = new ProgressIndicator();
gridPane.add(progressIndicator, 3, row);
progressIndicator.setPrefSize(18, 18);
if (walletFacade.getRegConfDepthInBlocks() == 0)
progressIndicator.setProgress(-1);
else
progressIndicator.setOpacity(0);
return progressIndicator;
}
public static ImageView addConfirmationsIcon(GridPane gridPane, WalletFacade walletFacade, int row)
{
int depthInBlocks = walletFacade.getRegConfNumBroadcastPeers();
int numBroadcastPeers = walletFacade.getRegConfDepthInBlocks();
Image confirmIconImage;
if (depthInBlocks > 0)
confirmIconImage = Icons.getIconImage(Icons.getIconIDForConfirmations(depthInBlocks));
else
confirmIconImage = Icons.getIconImage(Icons.getIconIDForPeersSeenTx(numBroadcastPeers));
ImageView confirmIconImageView = new ImageView(confirmIconImage);
gridPane.add(confirmIconImageView, 2, row);
return confirmIconImageView;
}
public static String getConfirmationText(WalletFacade walletFacade)
{
int numBroadcastPeers = walletFacade.getRegConfNumBroadcastPeers();
int depthInBlocks = walletFacade.getRegConfDepthInBlocks();
return depthInBlocks + " confirmation(s) / " + "Seen by " + numBroadcastPeers + " peer(s)";
}
} }

View file

@ -1,13 +1,13 @@
package io.bitsquare.gui.util; package io.bitsquare.gui.util;
import io.bitsquare.btc.BtcFormatter; import io.bitsquare.btc.BtcFormatter;
import io.bitsquare.settings.Settings;
import io.bitsquare.trade.Direction; import io.bitsquare.trade.Direction;
import java.math.BigInteger; import java.math.BigInteger;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.Currency; import java.util.Currency;
import java.util.List; import java.util.List;
import java.util.Locale;
public class Formatter public class Formatter
{ {
@ -111,7 +111,7 @@ public class Formatter
public static DecimalFormat getDecimalFormat(int fractionDigits) public static DecimalFormat getDecimalFormat(int fractionDigits)
{ {
DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Settings.getLocale()); DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Locale.getDefault());
decimalFormat.setMinimumFractionDigits(fractionDigits); decimalFormat.setMinimumFractionDigits(fractionDigits);
decimalFormat.setMaximumFractionDigits(fractionDigits); decimalFormat.setMaximumFractionDigits(fractionDigits);
decimalFormat.setGroupingUsed(false); decimalFormat.setGroupingUsed(false);
@ -123,4 +123,32 @@ public class Formatter
return value * 100 + "%"; return value * 100 + "%";
} }
public static String countryLocalesToString(List<Locale> countryLocales)
{
String result = "";
int i = 0;
for (Locale locale : countryLocales)
{
result += locale.getCountry();
i++;
if (i < countryLocales.size())
result += ", ";
}
return result;
}
public static String languageLocalesToString(List<Locale> languageLocales)
{
String result = "";
int i = 0;
for (Locale locale : languageLocales)
{
result += locale.getDisplayLanguage();
i++;
if (i < languageLocales.size())
result += ", ";
}
return result;
}
} }

View file

@ -4,7 +4,7 @@ import javafx.animation.AnimationTimer;
import java.util.function.Function; import java.util.function.Function;
public class Utils public class GUIUtils
{ {
/** /**
* @param delay in milliseconds * @param delay in milliseconds

View file

@ -1,194 +1,65 @@
package io.bitsquare.settings; package io.bitsquare.settings;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bitsquare.bank.BankAccountType;
import io.bitsquare.storage.Storage;
import io.bitsquare.trade.orderbook.OrderBookFilter;
import java.util.*; import java.io.Serializable;
import java.util.function.Predicate; import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class Settings public class Settings implements Serializable
{ {
private static final long serialVersionUID = 7995048077355006861L;
public static Locale locale = Locale.ENGLISH; private List<Locale> acceptedLanguageLocales = new ArrayList<>();
public static Currency currency = Currency.getInstance("USD"); private List<Locale> acceptedCountryLocales = new ArrayList<>();
private Storage storage;
private OrderBookFilter orderBookFilter;
public static Locale getLocale()
{
return Settings.locale;
}
public static Currency getCurrency()
{
return Settings.currency;
}
@Inject @Inject
public Settings(Storage storage, OrderBookFilter orderBookFilter) public Settings()
{ {
this.storage = storage;
this.orderBookFilter = orderBookFilter;
locale = Locale.ENGLISH;
currency = Currency.getInstance("USD");
currency = (Currency) storage.read("Settings.currency");
if (currency == null)
currency = Currency.getInstance("USD");
} }
public ArrayList<Locale> getAllLocales() public void updateFromStorage(Settings savedSettings)
{ {
ArrayList<Locale> list = new ArrayList<Locale>(Arrays.asList(Locale.getAvailableLocales())); if (savedSettings != null)
list.removeIf(new Predicate<Locale>()
{ {
@Override acceptedLanguageLocales = savedSettings.getAcceptedLanguageLocales();
public boolean test(Locale locale)
{
return locale == null || locale.getCountry().equals("") || locale.getLanguage().equals("");
}
});
list.sort(new Comparator<Locale>() acceptedCountryLocales = savedSettings.getAcceptedCountryLocales();
{ }
@Override
public int compare(Locale locale1, Locale locale2)
{
return locale1.getDisplayCountry().compareTo(locale2.getDisplayCountry());
}
});
Locale defaultLocale = Locale.getDefault();
list.remove(defaultLocale);
list.add(0, defaultLocale);
return list;
} }
public List<Currency> getAllCurrencies() public void addAcceptedLanguageLocale(Locale locale)
{ {
ArrayList<Currency> mainCurrencies = new ArrayList<>(); acceptedLanguageLocales.add(locale);
mainCurrencies.add(Currency.getInstance("USD"));
mainCurrencies.add(Currency.getInstance("EUR"));
mainCurrencies.add(Currency.getInstance("CNY"));
mainCurrencies.add(Currency.getInstance("RUB"));
mainCurrencies.add(Currency.getInstance("JPY"));
mainCurrencies.add(Currency.getInstance("GBP"));
mainCurrencies.add(Currency.getInstance("CAD"));
mainCurrencies.add(Currency.getInstance("AUD"));
mainCurrencies.add(Currency.getInstance("CHF"));
mainCurrencies.add(Currency.getInstance("CNY"));
Set<Currency> allCurrenciesSet = Currency.getAvailableCurrencies();
allCurrenciesSet.removeAll(mainCurrencies);
List<Currency> allCurrenciesList = new ArrayList<>(allCurrenciesSet);
allCurrenciesList.sort(new Comparator<Currency>()
{
@Override
public int compare(Currency a, Currency b)
{
return a.getCurrencyCode().compareTo(b.getCurrencyCode());
}
});
List<Currency> resultList = new ArrayList<>(mainCurrencies);
resultList.addAll(allCurrenciesList);
Currency defaultCurrency = Currency.getInstance(Locale.getDefault());
resultList.remove(defaultCurrency);
resultList.add(0, defaultCurrency);
return resultList;
} }
public ArrayList<BankAccountType.BankAccountTypeEnum> getAllBankAccountTypeEnums() public void addAcceptedCountryLocale(Locale locale)
{ {
ArrayList<BankAccountType.BankAccountTypeEnum> bankAccountTypeEnums = new ArrayList<>(); acceptedCountryLocales.add(locale);
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.SEPA);
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.WIRE);
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.INTERNATIONAL);
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.OK_PAY);
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.NET_TELLER);
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.PERFECT_MONEY);
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.OTHER);
return bankAccountTypeEnums;
} }
public ArrayList<BankAccountType> getAllBankAccountTypes() //setters
public void setAcceptedLanguageLocales(List<Locale> acceptedLanguageLocales)
{ {
ArrayList<BankAccountType> bankTransferTypes = new ArrayList<>(); this.acceptedLanguageLocales = acceptedLanguageLocales;
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.SEPA, "IBAN", "BIC")); }
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.WIRE, "Prim_todo", "Sec_todo"));
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.INTERNATIONAL, "Prim_todo", "Sec_todo")); public void setAcceptedCountryLocales(List<Locale> acceptedCountryLocales)
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.OK_PAY, "Prim_todo", "Sec_todo")); {
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.NET_TELLER, "Prim_todo", "Sec_todo")); this.acceptedCountryLocales = acceptedCountryLocales;
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.PERFECT_MONEY, "Prim_todo", "Sec_todo")); }
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.OTHER, "Prim_todo", "Sec_todo"));
return bankTransferTypes; //getters
public List<Locale> getAcceptedLanguageLocales()
{
return acceptedLanguageLocales;
} }
public ArrayList<String> getAllArbitrators() public List<Locale> getAcceptedCountryLocales()
{ {
ArrayList<String> arbitrators = new ArrayList<>(); return acceptedCountryLocales;
arbitrators.add("Paysty pool 1");
arbitrators.add("Paysty pool 2");
arbitrators.add("Paysty pool 3");
arbitrators.add("Paysty pool 4");
return arbitrators;
}
public ArrayList<String> getAllIdentityVerifications()
{
ArrayList<String> identityVerifications = new ArrayList<>();
identityVerifications.add("Passport");
identityVerifications.add("PGP");
identityVerifications.add("BTC-OTC");
identityVerifications.add("Bitcointalk");
identityVerifications.add("Reddit");
identityVerifications.add("Skype");
identityVerifications.add("Google+");
identityVerifications.add("Twitter");
identityVerifications.add("Diaspora");
identityVerifications.add("Facebook");
identityVerifications.add("Jabber");
identityVerifications.add("Other");
identityVerifications.add("Any");
identityVerifications.add("None");
return identityVerifications;
}
public ArrayList<String> getAllCollaterals()
{
ArrayList<String> list = new ArrayList<>();
list.add("0.01");
list.add("0.1");
list.add("0.5");
list.add("1.0");
return list;
}
public void setCurrency(Currency currency)
{
Settings.currency = currency;
storage.write("Settings.currency", currency);
}
public void setLocale(Locale locale)
{
Settings.locale = locale;
}
public OrderBookFilter getOrderBookFilter()
{
return orderBookFilter;
} }

View file

@ -1,32 +0,0 @@
package io.bitsquare.settings;
import com.google.inject.Inject;
import io.bitsquare.storage.Storage;
import io.bitsquare.trade.Direction;
import io.bitsquare.trade.orderbook.OrderBookFilter;
import io.bitsquare.user.User;
public class Startup
{
private Storage storage;
private User user;
private OrderBookFilter orderBookFilter;
@Inject
public Startup(Storage storage, OrderBookFilter orderBookFilter)
{
this.storage = storage;
this.orderBookFilter = orderBookFilter;
}
public void applyPersistedData()
{
// todo use persistence
orderBookFilter.setAmount(0.0);
orderBookFilter.setPrice(0.0);
orderBookFilter.setDirection(Direction.BUY);
orderBookFilter.setCurrency(Settings.getCurrency());
}
}

View file

@ -33,10 +33,6 @@ public class Storage
} }
} }
public void saveUser(User user)
{
write(user.getClass().getName(), user);
}
public void updateUserFromStorage(User user) public void updateUserFromStorage(User user)
{ {
@ -47,7 +43,7 @@ public class Storage
public void write(String key, Object value) public void write(String key, Object value)
{ {
log.info("Write object with key = " + key + " / value = " + value); //log.info("Write object with key = " + key + " / value = " + value);
dataVO.dict.put(key, value); dataVO.dict.put(key, value);
writeDataVO(dataVO); writeDataVO(dataVO);
} }
@ -56,7 +52,7 @@ public class Storage
{ {
dataVO = readDataVO(); dataVO = readDataVO();
Object result = dataVO.dict.get(key); Object result = dataVO.dict.get(key);
log.info("Read object with key = " + key + " result = " + result); //log.info("Read object with key = " + key + " result = " + result);
return result; return result;
} }

View file

@ -1,8 +1,10 @@
package io.bitsquare.trade; package io.bitsquare.trade;
import io.bitsquare.user.User; import io.bitsquare.bank.BankAccountType;
import java.util.Currency; import java.util.Currency;
import java.util.List;
import java.util.Locale;
import java.util.UUID; import java.util.UUID;
public class Offer public class Offer
@ -11,28 +13,110 @@ public class Offer
private double price; private double price;
private double amount; private double amount;
private double minAmount; private double minAmount;
private Direction direction;
private Currency currency;
private User offerer;
private OfferConstraints offerConstraints;
public Offer(UUID uid,
private String accountID;
private String messageID;
private Direction direction;
private BankAccountType.BankAccountTypeEnum bankAccountTypeEnum;
private Currency currency;
private Locale bankAccountCountryLocale;
private List<Locale> acceptedCountryLocales;
private List<Locale> acceptedLanguageLocales;
private String offerPaymentTxID;
public Offer(String accountID,
String messageID,
Direction direction, Direction direction,
double price, double price,
double amount, double amount,
double minAmount, double minAmount,
BankAccountType.BankAccountTypeEnum bankAccountTypeEnum,
Currency currency, Currency currency,
User offerer, Locale bankAccountCountryLocale,
OfferConstraints offerConstraints) List<Locale> acceptedCountryLocales,
List<Locale> acceptedLanguageLocales)
{ {
this.uid = uid; this.accountID = accountID;
this.messageID = messageID;
this.direction = direction; this.direction = direction;
this.price = price; this.price = price;
this.amount = amount; this.amount = amount;
this.minAmount = minAmount; this.minAmount = minAmount;
this.bankAccountTypeEnum = bankAccountTypeEnum;
this.currency = currency; this.currency = currency;
this.offerer = offerer; this.bankAccountCountryLocale = bankAccountCountryLocale;
this.offerConstraints = offerConstraints; this.acceptedCountryLocales = acceptedCountryLocales;
this.acceptedLanguageLocales = acceptedLanguageLocales;
uid = UUID.randomUUID();
}
// setter
public void setOfferPaymentTxID(String offerPaymentTxID)
{
this.offerPaymentTxID = offerPaymentTxID;
}
// getters
public String getAccountID()
{
return accountID;
}
public String getMessageID()
{
return messageID;
}
public UUID getUid()
{
return uid;
}
public double getPrice()
{
return price;
}
public double getAmount()
{
return amount;
}
public double getMinAmount()
{
return minAmount;
}
public Direction getDirection()
{
return direction;
}
public BankAccountType.BankAccountTypeEnum getBankAccountTypeEnum()
{
return bankAccountTypeEnum;
}
public Currency getCurrency()
{
return currency;
}
public Locale getBankAccountCountryLocale()
{
return bankAccountCountryLocale;
}
public List<Locale> getAcceptedCountryLocales()
{
return acceptedCountryLocales;
}
public List<Locale> getAcceptedLanguageLocales()
{
return acceptedLanguageLocales;
} }
public double getVolume() public double getVolume()
@ -45,85 +129,9 @@ public class Offer
return price * minAmount; return price * minAmount;
} }
public UUID getUid() public String getOfferPaymentTxID()
{ {
return uid; return offerPaymentTxID;
} }
public void setUid(UUID uid)
{
this.uid = uid;
}
public Direction getDirection()
{
return direction;
}
public void setDirection(Direction direction)
{
this.direction = direction;
}
public double getPrice()
{
return price;
}
public void setPrice(double price)
{
this.price = price;
}
public double getAmount()
{
return amount;
}
public void setAmount(double amount)
{
this.amount = amount;
}
public double getMinAmount()
{
return minAmount;
}
public void setMinAmount(double minAmount)
{
this.minAmount = minAmount;
}
public Currency getCurrency()
{
return currency;
}
public void setCurrency(Currency currency)
{
this.currency = currency;
}
public OfferConstraints getOfferConstraints()
{
return offerConstraints;
}
public void setOfferConstraints(OfferConstraints offerConstraints)
{
this.offerConstraints = offerConstraints;
}
public User getOfferer()
{
return offerer;
}
public void setOfferer(User offerer)
{
this.offerer = offerer;
}
} }

View file

@ -0,0 +1,29 @@
package io.bitsquare.trade;
import io.bitsquare.bank.BankAccountType;
import java.util.List;
import java.util.Locale;
public class OfferConstraint
{
private List<Locale> languageLocales;
private List<BankAccountType.BankAccountTypeEnum> bankAccountTypes;
public OfferConstraint(List<Locale> languageLocales,
List<BankAccountType.BankAccountTypeEnum> bankAccountTypes)
{
this.languageLocales = languageLocales;
this.bankAccountTypes = bankAccountTypes;
}
public List<Locale> getLanguageLocales()
{
return languageLocales;
}
public List<BankAccountType.BankAccountTypeEnum> getBankAccountTypes()
{
return bankAccountTypes;
}
}

View file

@ -1,73 +0,0 @@
package io.bitsquare.trade;
import io.bitsquare.bank.BankAccountType;
import java.util.List;
import java.util.Locale;
public class OfferConstraints
{
//TODO remove
private double collateral;
private String arbitrator;
private String identityVerification;
private List<Locale> countryLocales;
private List<Locale> languageLocales;
private List<BankAccountType.BankAccountTypeEnum> bankAccountTypes;
public OfferConstraints(List<Locale> countryLocales,
List<Locale> languageLocales,
double collateral,
List<BankAccountType.BankAccountTypeEnum> bankAccountTypes,
String arbitrator,
String identityVerification)
{
this.countryLocales = countryLocales;
this.languageLocales = languageLocales;
this.bankAccountTypes = bankAccountTypes;
this.collateral = collateral;
this.arbitrator = arbitrator;
this.identityVerification = identityVerification;
}
/**
* @return List of ISO3 country codes
*/
public List<Locale> getCountryLocales()
{
return countryLocales;
}
/**
* @return List of ISO3 language codes
*/
public List<Locale> getLanguageLocales()
{
return languageLocales;
}
public List<BankAccountType.BankAccountTypeEnum> getBankAccountTypes()
{
return bankAccountTypes;
}
public String getArbitrator()
{
return arbitrator;
}
public String getIdentityVerification()
{
return identityVerification;
}
public double getCollateral()
{
return collateral;
}
}

View file

@ -1,5 +1,6 @@
package io.bitsquare.trade; package io.bitsquare.trade;
import com.google.bitcoin.core.InsufficientMoneyException;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bitsquare.btc.BlockChainFacade; import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.btc.KeyPair; import io.bitsquare.btc.KeyPair;
@ -52,11 +53,15 @@ public class Trading
/** /**
* @param offer * @param offer
*/ */
public void placeNewOffer(Offer offer) public String placeNewOffer(Offer offer) throws InsufficientMoneyException
{ {
log.info("place New Offer"); log.info("place New Offer");
offers.put(offer.getUid().toString(), offer); offers.put(offer.getUid().toString(), offer);
String txID = walletFacade.payOfferFee();
offer.setOfferPaymentTxID(txID);
messageFacade.broadcast(new Message(Message.BROADCAST_NEW_OFFER, offer)); messageFacade.broadcast(new Message(Message.BROADCAST_NEW_OFFER, offer));
return txID;
} }
/** /**
@ -67,7 +72,7 @@ public class Trading
public void sendTakeOfferRequest(Trade trade) public void sendTakeOfferRequest(Trade trade)
{ {
log.info("Taker asks offerer to take his offer"); log.info("Taker asks offerer to take his offer");
messageFacade.send(new Message(Message.REQUEST_TAKE_OFFER, trade), trade.getOffer().getOfferer().getMessageID()); //messageFacade.send(new Message(Message.REQUEST_TAKE_OFFER, trade), trade.getOffer().getOfferer().getMessageID());
} }
@ -81,7 +86,7 @@ public class Trading
KeyPair address = walletFacade.createNewAddress(); KeyPair address = walletFacade.createNewAddress();
Contract contract = new Contract(trade, address.getPubKey()); Contract contract = new Contract(trade, address.getPubKey());
contract.setOfferer(trade.getOffer().getOfferer()); //contract.setOfferer(trade.getOffer().getOfferer());
contract.setTaker(user); contract.setTaker(user);
contracts.put(trade.getUid().toString(), contract); contracts.put(trade.getUid().toString(), contract);
return contract; return contract;
@ -132,7 +137,7 @@ public class Trading
trade.setTakeOfferFeeTxID(txID); trade.setTakeOfferFeeTxID(txID);
log.info("Taker asks offerer for confirmation for his fee payment. txID=" + txID); log.info("Taker asks offerer for confirmation for his fee payment. txID=" + txID);
messageFacade.send(new Message(Message.REQUEST_OFFER_FEE_PAYMENT_CONFIRM, trade), trade.getOffer().getOfferer().getMessageID()); // messageFacade.send(new Message(Message.REQUEST_OFFER_FEE_PAYMENT_CONFIRM, trade), trade.getOffer().getOfferer().getMessageID());
} }
@ -154,7 +159,7 @@ public class Trading
log.info("Sign deposit tx"); log.info("Sign deposit tx");
log.info("Send deposit Tx"); log.info("Send deposit Tx");
messageFacade.send(new Message(Message.REQUEST_OFFER_FEE_PAYMENT_CONFIRM, trade), trade.getOffer().getOfferer().getMessageID()); // messageFacade.send(new Message(Message.REQUEST_OFFER_FEE_PAYMENT_CONFIRM, trade), trade.getOffer().getOfferer().getMessageID());
} }
@ -168,7 +173,7 @@ public class Trading
log.info("Broadcast payment tx"); log.info("Broadcast payment tx");
log.info("Send message to peer that payment Tx has been broadcasted."); log.info("Send message to peer that payment Tx has been broadcasted.");
messageFacade.send(new Message(Message.REQUEST_OFFER_FEE_PAYMENT_CONFIRM, trade), trade.getOffer().getOfferer().getMessageID()); // messageFacade.send(new Message(Message.REQUEST_OFFER_FEE_PAYMENT_CONFIRM, trade), trade.getOffer().getOfferer().getMessageID());
} }

View file

@ -0,0 +1,118 @@
package io.bitsquare.trade.orderbook;
import com.google.inject.Inject;
import io.bitsquare.bank.BankAccountType;
import io.bitsquare.gui.trade.orderbook.OrderBookListItem;
import io.bitsquare.gui.util.Converter;
import io.bitsquare.gui.util.Formatter;
import io.bitsquare.settings.Settings;
import io.bitsquare.trade.Direction;
import io.bitsquare.trade.Offer;
import io.bitsquare.user.User;
import io.bitsquare.util.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
public class MockOrderBook extends OrderBook
{
private static final Logger log = LoggerFactory.getLogger(MockOrderBook.class);
@Inject
public MockOrderBook(Settings settings, User user)
{
super(settings, user);
for (int i = 0; i < 1000; i++)
{
allOffers.add(new OrderBookListItem(getOffer()));
}
}
private Offer getOffer()
{
double amount = Math.random() * 10 + 0.1;
amount = Converter.stringToDouble(Formatter.formatAmount(amount));
double minAmount = Math.random() * amount;
minAmount = Converter.stringToDouble(Formatter.formatAmount(minAmount));
Direction direction = Direction.BUY;
double price = 500 + Math.random() * 50;
if (Math.random() > 0.5)
{
direction = Direction.SELL;
price = 500 - Math.random() * 50;
}
Offer offer = new Offer(UUID.randomUUID().toString(),
UUID.randomUUID().toString(),
direction,
price,
amount,
minAmount,
getBankTransferTypeEnums().get(0),
getCurrencies().get(0),
getLocales().get(0),
getLocales(),
getLocales());
return offer;
}
private List<Currency> getCurrencies()
{
List<Currency> list = new ArrayList<>();
list.add(Currency.getInstance("EUR"));
list.add(Currency.getInstance("USD"));
list.add(Currency.getInstance("GBP"));
list.add(Currency.getInstance("RUB"));
list.add(Currency.getInstance("CAD"));
list.add(Currency.getInstance("AUD"));
list.add(Currency.getInstance("JPY"));
list.add(Currency.getInstance("CNY"));
list.add(Currency.getInstance("CHF"));
return randomizeList(list);
}
private List<Locale> getLocales()
{
List<Locale> list = new ArrayList<>();
list.add(new Locale("de", "AT"));
list.add(new Locale("de", "DE"));
list.add(new Locale("en", "US"));
list.add(new Locale("en", "UK"));
list.add(new Locale("es", "ES"));
list.add(new Locale("ru", "RU"));
list.add(new Locale("zh", "CN"));
list.add(new Locale("en", "AU"));
list.add(new Locale("it", "IT"));
list.add(new Locale("en", "CA"));
return randomizeList(list);
}
private List<BankAccountType.BankAccountTypeEnum> getBankTransferTypeEnums()
{
return randomizeList(Utils.getAllBankAccountTypeEnums());
}
private List randomizeList(List list)
{
int e = new Random().nextInt(list.size());
if (list.size() > 0)
e = Math.max(e, 1);
int s = (e == 0) ? 0 : new Random().nextInt(e);
list = list.subList(s, e);
return list;
}
private List reduce(List list, int count)
{
List result = new ArrayList();
for (int i = 0; i < count && i < list.size(); i++)
{
result.add(list.get(i));
}
return result;
}
}

View file

@ -1,239 +1,167 @@
package io.bitsquare.trade.orderbook; package io.bitsquare.trade.orderbook;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.bank.BankAccountType; import io.bitsquare.bank.BankAccountType;
import io.bitsquare.gui.trade.orderbook.OrderBookListItem; import io.bitsquare.gui.trade.orderbook.OrderBookListItem;
import io.bitsquare.gui.util.Converter;
import io.bitsquare.gui.util.Formatter;
import io.bitsquare.settings.Settings; import io.bitsquare.settings.Settings;
import io.bitsquare.trade.Direction; import io.bitsquare.trade.Direction;
import io.bitsquare.trade.Offer; import io.bitsquare.trade.Offer;
import io.bitsquare.trade.OfferConstraints;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList; import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*; import java.util.List;
import java.util.Locale;
import java.util.function.Predicate; import java.util.function.Predicate;
public class OrderBook public class OrderBook
{ {
private ObservableList<OrderBookListItem> orderBookListItems; private static final Logger log = LoggerFactory.getLogger(OrderBook.class);
private FilteredList<OrderBookListItem> filteredList;
private SortedList<OrderBookListItem> offerList;
protected ObservableList<OrderBookListItem> allOffers = FXCollections.observableArrayList();
private Settings settings; private Settings settings;
private User user;
@Inject @Inject
public OrderBook(Settings settings) public OrderBook(Settings settings, User user)
{ {
this.settings = settings; this.settings = settings;
orderBookListItems = FXCollections.observableArrayList(); this.user = user;
for (int i = 0; i < 100; i++)
{ filteredList = new FilteredList<>(allOffers);
orderBookListItems.add(getOrderBookListItem()); // FilteredList does not support sorting, so we need to wrap it to a SortedList
} offerList = new SortedList<>(filteredList);
} }
public ObservableList<OrderBookListItem> getFilteredList(OrderBookFilter orderBookFilter) public SortedList<OrderBookListItem> getOfferList()
{ {
FilteredList filtered = orderBookListItems.filtered(new Predicate<OrderBookListItem>() return offerList;
}
public void updateFilter(OrderBookFilter orderBookFilter)
{
filteredList.setPredicate(new Predicate<OrderBookListItem>()
{ {
@Override @Override
public boolean test(OrderBookListItem offerListVO) public boolean test(OrderBookListItem orderBookListItem)
{ {
boolean priceResult; Offer offer = orderBookListItem.getOffer();
boolean amountResult = offerListVO.getOffer().getAmount() >= orderBookFilter.getAmount(); BankAccount currentBankAccount = user.getCurrentBankAccount();
// swap direction. use who want to buy btc want to see sell offers...
boolean directionResult = offerListVO.getOffer().getDirection() != orderBookFilter.getDirection();
boolean currencyResult = offerListVO.getOffer().getCurrency().equals(orderBookFilter.getCurrency());
if (offerListVO.getOffer().getDirection() == Direction.SELL && orderBookFilter.getPrice() > 0) if (orderBookFilter == null
priceResult = offerListVO.getOffer().getPrice() <= orderBookFilter.getPrice(); || offer == null
else || currentBankAccount == null
priceResult = offerListVO.getOffer().getPrice() >= orderBookFilter.getPrice(); || orderBookFilter.getDirection() == null)
return priceResult && amountResult && directionResult && currencyResult; return false;
// The users current bank account currency must match the offer currency (1 to 1)
boolean currencyResult = currentBankAccount.getCurrency().equals(offer.getCurrency());
// The offer bank account country must match one of the accepted countries defined in the settings (1 to n)
boolean countryResult = countryInList(offer.getBankAccountCountryLocale(), settings.getAcceptedCountryLocales());
// One of the supported languages from the settings must match one of the offer languages (n to n)
boolean languageResult = languagesInList(settings.getAcceptedLanguageLocales(), offer.getAcceptedLanguageLocales());
// Apply updateFilter only if there is a valid value set
// The requested amount must be lower or equal then the offer amount
boolean amountResult = true;
if (orderBookFilter.getAmount() > 0)
amountResult = orderBookFilter.getAmount() <= offer.getAmount();
// The requested trade direction must be opposite of the offerList trade direction
boolean directionResult = !orderBookFilter.getDirection().equals(offer.getDirection());
// Apply updateFilter only if there is a valid value set
boolean priceResult = true;
if (orderBookFilter.getPrice() > 0)
{
if (offer.getDirection() == Direction.SELL)
priceResult = orderBookFilter.getPrice() >= offer.getPrice();
else
priceResult = orderBookFilter.getPrice() <= offer.getPrice();
}
boolean result = currencyResult
&& countryResult
&& languageResult
&& amountResult
&& directionResult
&& priceResult;
/*
log.debug("result = " + result +
", currencyResult = " + currencyResult +
", countryResult = " + countryResult +
", languageResult = " + languageResult +
", bankAccountTypeEnumResult = " + bankAccountTypeEnumResult +
", amountResult = " + amountResult +
", directionResult = " + directionResult +
", priceResult = " + priceResult
);
log.debug("currentBankAccount.getCurrency() = " + currentBankAccount.getCurrency() +
", offer.getCurrency() = " + offer.getCurrency());
log.debug("offer.getCountryLocale() = " + offer.getCountryLocale() +
", settings.getAcceptedCountryLocales() = " + settings.getAcceptedCountryLocales().toString());
log.debug("settings.getAcceptedLanguageLocales() = " + settings.getAcceptedLanguageLocales() +
", constraints.getAcceptedLanguageLocales() = " + constraints.getLanguageLocales());
log.debug("currentBankAccount.getBankAccountType().getType() = " + currentBankAccount.getBankAccountType().getType() +
", constraints.getBankAccountTypes() = " + constraints.getBankAccountTypes());
log.debug("orderBookFilter.getAmount() = " + orderBookFilter.getAmount() +
", offer.getAmount() = " + offer.getAmount());
log.debug("orderBookFilter.getDirection() = " + orderBookFilter.getDirection() +
", offer.getDirection() = " + offer.getDirection());
log.debug("orderBookFilter.getPrice() = " + orderBookFilter.getPrice() +
", offer.getPrice() = " + offer.getPrice());
*/
return result;
} }
}); });
//TODO use FilteredList
ObservableList<OrderBookListItem> result = FXCollections.observableArrayList();
result.addAll(filtered);
return result;
} }
private OrderBookListItem getOrderBookListItem() private boolean countryInList(Locale orderBookFilterLocale, List<Locale> offerConstraintsLocales)
{ {
return new OrderBookListItem(getOffer()); for (Locale locale : offerConstraintsLocales)
}
public ArrayList<Currency> getCurrencies()
{
ArrayList<Currency> currencies = new ArrayList<>();
currencies.add(Currency.getInstance("USD"));
currencies.add(Currency.getInstance("EUR"));
currencies.add(Currency.getInstance("CNY"));
currencies.add(Currency.getInstance("RUB"));
currencies.add(Currency.getInstance("JPY"));
currencies.add(Currency.getInstance("GBP"));
currencies.add(Currency.getInstance("CAD"));
currencies.add(Currency.getInstance("AUD"));
currencies.add(Currency.getInstance("CHF"));
currencies.add(Currency.getInstance("CNY"));
/* Set<Currency> otherCurrenciesSet = Currency.getAvailableCurrencies();
ArrayList<Currency> otherCurrenciesList = new ArrayList<>();
otherCurrenciesList.addAll(otherCurrenciesSet);
Collections.sort(otherCurrenciesList, new CurrencyComparator());
currencies.addAll(otherCurrenciesList); */
return currencies;
}
private Offer getOffer()
{
User offerer = new User();
offerer.setAccountID(UUID.randomUUID().toString());
offerer.setMessageID(UUID.randomUUID().toString());
offerer.setOnline(Math.random() > 0.5 ? true : false);
offerer.setLanguageLocales(getLanguageLocales());
double amount = Math.random() * 10 + 0.1;
amount = Converter.convertToDouble(Formatter.formatAmount(amount));
double minAmount = Math.random() * amount;
minAmount = Converter.convertToDouble(Formatter.formatAmount(minAmount));
Direction direction = Direction.BUY;
double price = 500 + Math.random() * 50;
if (Math.random() > 0.5)
{ {
direction = Direction.SELL; if (locale.getCountry().equals(orderBookFilterLocale.getCountry()))
price = 500 - Math.random() * 50; return true;
} }
Currency currency = (randomizeCurrencies(getCurrencies(), false)).get(0); return false;
return new Offer(UUID.randomUUID(),
direction,
price,
amount,
minAmount,
currency,
offerer,
getRandomOfferConstraints()
);
} }
public OfferConstraints getRandomOfferConstraints() private boolean languagesInList(List<Locale> orderBookFilterLocales, List<Locale> offerConstraintsLocales)
{ {
OfferConstraints offerConstraints = new OfferConstraints(getCountryLocales(), for (Locale offerConstraintsLocale : offerConstraintsLocales)
getLanguageLocales(), {
Double.valueOf(getCollaterals().get(0)), for (Locale orderBookFilterLocale : orderBookFilterLocales)
getBankTransferTypeEnums(), {
getArbitrators().get(0), if (offerConstraintsLocale.getLanguage().equals(orderBookFilterLocale.getLanguage()))
randomizeStrings(settings.getAllIdentityVerifications(), false).get(0)); return true;
}
return offerConstraints; }
return false;
} }
private boolean matchBankAccountTypeEnum(BankAccountType.BankAccountTypeEnum orderBookFilterBankAccountType, List<BankAccountType.BankAccountTypeEnum> offerConstraintsBankAccountTypes)
private List<Locale> getCountryLocales()
{ {
for (BankAccountType.BankAccountTypeEnum bankAccountType : offerConstraintsBankAccountTypes)
return randomizeList(settings.getAllLocales(), false); {
} if (bankAccountType.equals(orderBookFilterBankAccountType))
return true;
private List<Locale> getLanguageLocales() }
{ return false;
return randomizeList(settings.getAllLocales(), false);
} }
private List<BankAccountType> getBankTransferTypes()
{
return randomizeBankAccountTypes(settings.getAllBankAccountTypes(), false);
}
private List<BankAccountType.BankAccountTypeEnum> getBankTransferTypeEnums()
{
return randomizeBankAccountTypeEnums(settings.getAllBankAccountTypeEnums(), false);
}
private List<String> getArbitrators()
{
return randomizeStrings(settings.getAllArbitrators(), false);
}
private List<String> getCollaterals()
{
return randomizeStrings(settings.getAllCollaterals(), false);
}
private List<BankAccountType.BankAccountTypeEnum> randomizeBankAccountTypeEnums(List<BankAccountType.BankAccountTypeEnum> list, boolean optional)
{
int e = new Random().nextInt(list.size());
if (!optional && list.size() > 0)
e = Math.max(e, 1);
int s = (e == 0) ? 0 : new Random().nextInt(e);
list = list.subList(s, e);
return list;
}
private List<BankAccountType> randomizeBankAccountTypes(List<BankAccountType> list, boolean optional)
{
int e = new Random().nextInt(list.size());
if (!optional && list.size() > 0)
e = Math.max(e, 1);
int s = (e == 0) ? 0 : new Random().nextInt(e);
list = list.subList(s, e);
return list;
}
private List<String> randomizeStrings(List<String> list, boolean optional)
{
int e = new Random().nextInt(list.size());
if (!optional && list.size() > 0)
e = Math.max(e, 1);
int s = (e == 0) ? 0 : new Random().nextInt(e);
list = list.subList(s, e);
return list;
}
private List randomizeList(List list, boolean optional)
{
int e = new Random().nextInt(list.size());
if (!optional && list.size() > 0)
e = Math.max(e, 1);
int s = (e == 0) ? 0 : new Random().nextInt(e);
list = list.subList(s, e);
return list;
}
private List<Double> randomizeDouble(List<Double> list, boolean optional)
{
int e = new Random().nextInt(list.size());
if (!optional && list.size() > 0)
e = Math.max(e, 1);
int s = (e == 0) ? 0 : new Random().nextInt(e);
list = list.subList(s, e);
return list;
}
private List<Currency> randomizeCurrencies(List<Currency> list, boolean optional)
{
int e = new Random().nextInt(list.size());
if (!optional && list.size() > 0)
e = Math.max(e, 1);
int s = (e == 0) ? 0 : new Random().nextInt(e);
list = list.subList(s, e);
return list;
}
} }
class CurrencyComparator implements Comparator<Currency>
{
@Override
public int compare(Currency a, Currency b)
{
return a.getCurrencyCode().compareTo(b.getCurrencyCode());
}
}

View file

@ -1,36 +1,17 @@
package io.bitsquare.trade.orderbook; package io.bitsquare.trade.orderbook;
import io.bitsquare.trade.Direction; import io.bitsquare.trade.Direction;
import io.bitsquare.trade.OfferConstraints;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
import java.util.Currency;
import java.util.Locale;
public class OrderBookFilter public class OrderBookFilter
{ {
transient private final SimpleBooleanProperty changedProperty = new SimpleBooleanProperty();
private double price; private double price;
private double amount; private double amount;
private Direction direction; private Direction direction;
private Currency currency;
private Locale countryLocale;
private Locale languageLocale;
private OfferConstraints offerConstraints;
public SimpleBooleanProperty changedPropertyProperty()
{
return changedProperty;
}
private final SimpleBooleanProperty changedProperty = new SimpleBooleanProperty();
// setters // setters
public void setCurrency(Currency currency)
{
this.currency = currency;
triggerChange();
}
public void setAmount(double amount) public void setAmount(double amount)
{ {
@ -50,23 +31,6 @@ public class OrderBookFilter
triggerChange(); triggerChange();
} }
public void setOfferConstraints(OfferConstraints offerConstraints)
{
this.offerConstraints = offerConstraints;
triggerChange();
}
public void setCountryLocale(Locale countryLocale)
{
this.countryLocale = countryLocale;
triggerChange();
}
public void setLanguageLocale(Locale languageLocale)
{
this.languageLocale = languageLocale;
triggerChange();
}
// getters // getters
public double getAmount() public double getAmount()
@ -84,25 +48,6 @@ public class OrderBookFilter
return price; return price;
} }
public Currency getCurrency()
{
return currency;
}
public OfferConstraints getOfferConstraints()
{
return offerConstraints;
}
public Locale getCountryLocale()
{
return countryLocale;
}
public Locale getLanguageLocale()
{
return languageLocale;
}
public SimpleBooleanProperty getChangedProperty() public SimpleBooleanProperty getChangedProperty()
{ {
@ -113,4 +58,5 @@ public class OrderBookFilter
{ {
changedProperty.set(!changedProperty.get()); changedProperty.set(!changedProperty.get());
} }
} }

View file

@ -1,28 +1,30 @@
package io.bitsquare.user; package io.bitsquare.user;
import io.bitsquare.bank.BankAccount; import io.bitsquare.bank.BankAccount;
import io.bitsquare.trade.OfferConstraint;
import javafx.beans.property.SimpleBooleanProperty;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
public class User implements Serializable public class User implements Serializable
{ {
private static final long serialVersionUID = 7409078808248518638L; private static final long serialVersionUID = 7409078808248518638L;
transient private final SimpleBooleanProperty changedProperty = new SimpleBooleanProperty();
private String accountID; private String accountID;
private String messageID; private String messageID;
private boolean online; private boolean online;
private List<BankAccount> bankAccounts = new ArrayList<>(); private List<BankAccount> bankAccounts = new ArrayList<>();
private BankAccount currentBankAccount = null; private BankAccount currentBankAccount = null;
private List<Locale> languageLocales = new ArrayList<>();
private Locale currentLanguageLocale = null; private OfferConstraint offerConstraint;
public User() public User()
{ {
addLanguageLocales(Locale.getDefault());
} }
public void updateFromStorage(User savedUser) public void updateFromStorage(User savedUser)
@ -34,8 +36,6 @@ public class User implements Serializable
online = savedUser.isOnline(); online = savedUser.isOnline();
currentBankAccount = savedUser.getCurrentBankAccount(); currentBankAccount = savedUser.getCurrentBankAccount();
bankAccounts = savedUser.getBankAccounts(); bankAccounts = savedUser.getBankAccounts();
languageLocales = savedUser.getLanguageLocales();
currentLanguageLocale = savedUser.getCurrentLanguageLocale();
} }
} }
@ -53,15 +53,8 @@ public class User implements Serializable
return bankAccountUIDs; return bankAccountUIDs;
} }
public void addLanguageLocales(Locale locale)
{
languageLocales.add(locale);
currentLanguageLocale = locale;
}
public void addBankAccount(BankAccount bankAccount) public void addBankAccount(BankAccount bankAccount)
{ {
bankAccounts.add(bankAccount); bankAccounts.add(bankAccount);
currentBankAccount = bankAccount; currentBankAccount = bankAccount;
} }
@ -77,7 +70,6 @@ public class User implements Serializable
this.accountID = accountID; this.accountID = accountID;
} }
public void setBankAccounts(List<BankAccount> bankAccounts) public void setBankAccounts(List<BankAccount> bankAccounts)
{ {
this.bankAccounts = bankAccounts; this.bankAccounts = bankAccounts;
@ -86,23 +78,19 @@ public class User implements Serializable
public void setCurrentBankAccount(BankAccount currentBankAccount) public void setCurrentBankAccount(BankAccount currentBankAccount)
{ {
this.currentBankAccount = currentBankAccount; this.currentBankAccount = currentBankAccount;
triggerChange();
} }
public void setLanguageLocales(List<Locale> languageLocales)
{
this.languageLocales = languageLocales;
}
public void setCurrentLanguageLocale(Locale currentLanguageLocale)
{
this.currentLanguageLocale = currentLanguageLocale;
}
public void setOnline(boolean online) public void setOnline(boolean online)
{ {
this.online = online; this.online = online;
} }
public void setOfferConstraint(OfferConstraint offerConstraint)
{
this.offerConstraint = offerConstraint;
}
// getter // getter
public String getMessageID() public String getMessageID()
@ -125,20 +113,24 @@ public class User implements Serializable
return currentBankAccount; return currentBankAccount;
} }
public List<Locale> getLanguageLocales()
{
return languageLocales;
}
public Locale getCurrentLanguageLocale()
{
return currentLanguageLocale;
}
public boolean isOnline() public boolean isOnline()
{ {
return online; return online;
} }
public OfferConstraint getOfferConstraint()
{
return offerConstraint;
}
public SimpleBooleanProperty getChangedProperty()
{
return changedProperty;
}
private void triggerChange()
{
changedProperty.set(!changedProperty.get());
}
} }

View file

@ -3,17 +3,40 @@ package io.bitsquare.util;
import com.google.gson.FieldNamingPolicy; import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import io.bitsquare.bank.BankAccountType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*; import java.io.*;
import java.util.*;
import java.util.function.Predicate;
public class Utils public class Utils
{ {
private static final Logger log = LoggerFactory.getLogger(Utils.class);
public static String convertToJson(Object object) public static String convertToJson(Object object)
{ {
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create(); Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
return gson.toJson(object); return gson.toJson(object);
} }
private static long lastTimeStamp = System.currentTimeMillis();
public static void printElapsedTime(String msg)
{
if (msg.length() > 0)
msg += " / ";
long timeStamp = System.currentTimeMillis();
log.debug(msg + "Elapsed: " + String.valueOf(timeStamp - lastTimeStamp));
lastTimeStamp = timeStamp;
}
public static void printElapsedTime()
{
printElapsedTime("");
}
public static Object copy(Object orig) public static Object copy(Object orig)
{ {
Object obj = null; Object obj = null;
@ -40,4 +63,97 @@ public class Utils
return obj; return obj;
} }
public static ArrayList<Locale> getAllLocales()
{
ArrayList<Locale> list = new ArrayList<Locale>(Arrays.asList(Locale.getAvailableLocales()));
list.removeIf(new Predicate<Locale>()
{
@Override
public boolean test(Locale locale)
{
return locale == null || locale.getCountry().equals("") || locale.getLanguage().equals("");
}
});
list.sort(new Comparator<Locale>()
{
@Override
public int compare(Locale locale1, Locale locale2)
{
return locale1.getDisplayCountry().compareTo(locale2.getDisplayCountry());
}
});
Locale defaultLocale = Locale.getDefault();
//Locale defaultLocale = new Locale("de", "AT");
list.remove(defaultLocale);
list.add(0, defaultLocale);
return list;
}
public static List<Currency> getAllCurrencies()
{
ArrayList<Currency> mainCurrencies = new ArrayList<>();
mainCurrencies.add(Currency.getInstance("USD"));
mainCurrencies.add(Currency.getInstance("EUR"));
mainCurrencies.add(Currency.getInstance("CNY"));
mainCurrencies.add(Currency.getInstance("RUB"));
mainCurrencies.add(Currency.getInstance("JPY"));
mainCurrencies.add(Currency.getInstance("GBP"));
mainCurrencies.add(Currency.getInstance("CAD"));
mainCurrencies.add(Currency.getInstance("AUD"));
mainCurrencies.add(Currency.getInstance("CHF"));
mainCurrencies.add(Currency.getInstance("CNY"));
Set<Currency> allCurrenciesSet = Currency.getAvailableCurrencies();
allCurrenciesSet.removeAll(mainCurrencies);
List<Currency> allCurrenciesList = new ArrayList<>(allCurrenciesSet);
allCurrenciesList.sort(new Comparator<Currency>()
{
@Override
public int compare(Currency a, Currency b)
{
return a.getCurrencyCode().compareTo(b.getCurrencyCode());
}
});
List<Currency> resultList = new ArrayList<>(mainCurrencies);
resultList.addAll(allCurrenciesList);
Currency defaultCurrency = Currency.getInstance(Locale.getDefault());
resultList.remove(defaultCurrency);
resultList.add(0, defaultCurrency);
return resultList;
}
public static ArrayList<BankAccountType.BankAccountTypeEnum> getAllBankAccountTypeEnums()
{
ArrayList<BankAccountType.BankAccountTypeEnum> bankAccountTypeEnums = new ArrayList<>();
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.SEPA);
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.WIRE);
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.INTERNATIONAL);
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.OK_PAY);
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.NET_TELLER);
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.PERFECT_MONEY);
bankAccountTypeEnums.add(BankAccountType.BankAccountTypeEnum.OTHER);
return bankAccountTypeEnums;
}
public static ArrayList<BankAccountType> getAllBankAccountTypes()
{
ArrayList<BankAccountType> bankTransferTypes = new ArrayList<>();
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.SEPA, "IBAN", "BIC"));
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.WIRE, "Prim_todo", "Sec_todo"));
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.INTERNATIONAL, "Prim_todo", "Sec_todo"));
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.OK_PAY, "Prim_todo", "Sec_todo"));
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.NET_TELLER, "Prim_todo", "Sec_todo"));
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.PERFECT_MONEY, "Prim_todo", "Sec_todo"));
bankTransferTypes.add(new BankAccountType(BankAccountType.BankAccountTypeEnum.OTHER, "Prim_todo", "Sec_todo"));
return bankTransferTypes;
}
} }

View file

Before

Width:  |  Height:  |  Size: 599 B

After

Width:  |  Height:  |  Size: 599 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 157 B

After

Width:  |  Height:  |  Size: 157 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 573 B

After

Width:  |  Height:  |  Size: 573 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 205 B

After

Width:  |  Height:  |  Size: 205 B

Before After
Before After