diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..89362a333a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+/docs
+/log
+/target
+/bin
+.idea
+bitsquare.iml
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000000..57418495d6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific languages governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/README.md b/README.md
index 9a84d8fb3f..ec5b58f6ca 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,35 @@
-www.bitsquare.io
-=====
+bitsquare.io
+===
+
+Bitsquare is a P2P Fiat-BTC Exchange, extensible to a generic P2P trading platform (include commodities and
+cryptocurrencies)
+
+This is just a first very basic GUI prototype with mock data.
+There is only the trade process for Sell BTC and the role of the offer taker modelled yet.
+
+Done:
+* Screen for orderbook with filtering mock offers by amount, price and order type (buy, sell), other filters not impl. yet
+* Screen for creating an offer (needs update)
+* Screen for offer taking and payment process
+* Simple storage for some filter attributes
+
+
+Next steps:
+* Other trade variants (Buy BTC taker, Sell BTC offerer, Sell BTC offerer)
+* Arbitrator integration
+* bitcoinj integration
+* messaging system
+* ...
+
+
+The project use Java 8 and Maven.
+
+
+Web: http://bitsquare.io
+
+Whitepaper: https://docs.google.com/document/d/1d3EiWZdaM89-P6MVhS53unXv2-pDpSFsN3W4kCGXKgY/edit?pli=1
+
+Overview: http://bitsquare.io/images/overview.png
+
+Discussion: https://bitcointalk.org/index.php?topic=462236
+
diff --git a/design/navIcons.psd b/design/navIcons.psd
new file mode 100644
index 0000000000..bf371e550d
Binary files /dev/null and b/design/navIcons.psd differ
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000000..4baf9de8df
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,89 @@
+
+
+ 4.0.0
+
+ bitsquare
+ bitsquare
+ 0.1
+
+ BitSquare
+ A P2P Fiat-Bitcoin Exchange
+ https://www.bitsquare.io
+
+
+
+ Apache 2
+ http://www.apache.org/licenses/LICENSE-2.0
+ repo
+
+
+
+
+ https://github.com/bitsquare/bitsquare
+
+
+
+
+
+ src/main/java
+
+
+ src/main/resources
+
+
+
+
+
+
+ junit
+ junit
+ 4.11
+ test
+
+
+
+ org.slf4j
+ slf4j-api
+ 1.7.6
+
+
+
+ ch.qos.logback
+ logback-classic
+ 1.0.9
+ compile
+
+
+
+ com.google.inject
+ guice
+ 3.0
+
+
+
+ com.google.guava
+ guava-base
+ r03
+
+
+
+ com.google.code.gson
+ gson
+ 2.2.4
+ compile
+
+
+
+ org.controlsfx
+ controlsfx
+ 8.0.5
+
+
+
+
+
+ UTF-8
+
+
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/BitSquare.java b/src/main/java/io/bitsquare/BitSquare.java
new file mode 100644
index 0000000000..68293cf0f6
--- /dev/null
+++ b/src/main/java/io/bitsquare/BitSquare.java
@@ -0,0 +1,51 @@
+package io.bitsquare;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import io.bitsquare.di.BitSquareModule;
+import io.bitsquare.di.GuiceFXMLLoader;
+import io.bitsquare.setup.ISetup;
+import io.bitsquare.setup.MockSetup;
+import javafx.application.Application;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+public class BitSquare extends Application
+{
+ private static final Logger log = LoggerFactory.getLogger(BitSquare.class);
+
+ public static void main(String[] args)
+ {
+ launch(args);
+ }
+
+ @Override
+ public void start(Stage stage)
+ {
+ Injector injector = Guice.createInjector(new BitSquareModule());
+ ISetup setup = injector.getInstance(MockSetup.class);
+
+ setup.applyPersistedData();
+
+ stage.setTitle("BitSquare");
+
+ GuiceFXMLLoader loader = new GuiceFXMLLoader(injector);
+ try
+ {
+ Parent mainView = loader.load(BitSquare.class.getResourceAsStream("/io/bitsquare/gui/MainView.fxml"));
+ Scene scene = new Scene(mainView, 800, 600);
+ scene.getStylesheets().setAll(getClass().getResource("/io/bitsquare/gui/global.css").toExternalForm());
+ stage.setScene(scene);
+ stage.show();
+ } catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/main/java/io/bitsquare/btc/BlockChainFacade.java b/src/main/java/io/bitsquare/btc/BlockChainFacade.java
new file mode 100644
index 0000000000..0e8c1a1c52
--- /dev/null
+++ b/src/main/java/io/bitsquare/btc/BlockChainFacade.java
@@ -0,0 +1,17 @@
+package io.bitsquare.btc;
+
+import com.google.inject.Inject;
+
+/**
+ * Gateway to blockchain
+ */
+public class BlockChainFacade
+{
+ @Inject
+ public BlockChainFacade()
+ {
+
+ }
+
+
+}
diff --git a/src/main/java/io/bitsquare/btc/BtcFormatter.java b/src/main/java/io/bitsquare/btc/BtcFormatter.java
new file mode 100644
index 0000000000..9a6d2cf9d8
--- /dev/null
+++ b/src/main/java/io/bitsquare/btc/BtcFormatter.java
@@ -0,0 +1,15 @@
+package io.bitsquare.btc;
+
+import java.math.BigInteger;
+
+public class BtcFormatter
+{
+ public static BigInteger BTC = new BigInteger("100000000");
+ public static BigInteger mBTC = new BigInteger("100000");
+
+ //TODO
+ public static double satoshiToBTC(BigInteger satoshis)
+ {
+ return satoshis.doubleValue() / BTC.doubleValue();
+ }
+}
diff --git a/src/main/java/io/bitsquare/btc/Fees.java b/src/main/java/io/bitsquare/btc/Fees.java
new file mode 100644
index 0000000000..b3cdbc5482
--- /dev/null
+++ b/src/main/java/io/bitsquare/btc/Fees.java
@@ -0,0 +1,11 @@
+package io.bitsquare.btc;
+
+import java.math.BigInteger;
+
+public class Fees
+{
+ public static BigInteger OFFER_CREATION_FEE = new BigInteger("500000");
+ public static BigInteger OFFER_TAKER_FEE = OFFER_CREATION_FEE;
+ public static BigInteger BTC_NETWORK_FEE = new BigInteger("10000");
+
+}
diff --git a/src/main/java/io/bitsquare/btc/IWalletFacade.java b/src/main/java/io/bitsquare/btc/IWalletFacade.java
new file mode 100644
index 0000000000..3981da16bb
--- /dev/null
+++ b/src/main/java/io/bitsquare/btc/IWalletFacade.java
@@ -0,0 +1,12 @@
+package io.bitsquare.btc;
+
+import java.math.BigInteger;
+
+public interface IWalletFacade
+{
+ BigInteger getBalance();
+
+ boolean pay(BigInteger satoshisToPay, String destinationAddress);
+
+ KeyPair createNewAddress();
+}
diff --git a/src/main/java/io/bitsquare/btc/KeyPair.java b/src/main/java/io/bitsquare/btc/KeyPair.java
new file mode 100644
index 0000000000..67a60eab20
--- /dev/null
+++ b/src/main/java/io/bitsquare/btc/KeyPair.java
@@ -0,0 +1,33 @@
+package io.bitsquare.btc;
+
+public class KeyPair
+{
+ private String pubKey;
+ private String privKey;
+
+ public KeyPair(String pubKey, String privKey)
+ {
+ this.pubKey = pubKey;
+ this.privKey = privKey;
+ }
+
+ public String getPrivKey()
+ {
+ return privKey;
+ }
+
+ public void setPrivKey(String privKey)
+ {
+ this.privKey = privKey;
+ }
+
+ public String getPubKey()
+ {
+ return pubKey;
+ }
+
+ public void setPubKey(String pubKey)
+ {
+ this.pubKey = pubKey;
+ }
+}
diff --git a/src/main/java/io/bitsquare/btc/MockWalletFacade.java b/src/main/java/io/bitsquare/btc/MockWalletFacade.java
new file mode 100644
index 0000000000..3443a2bdbe
--- /dev/null
+++ b/src/main/java/io/bitsquare/btc/MockWalletFacade.java
@@ -0,0 +1,52 @@
+package io.bitsquare.btc;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.UUID;
+
+/**
+ * Gateway to wallet
+ */
+public class MockWalletFacade implements IWalletFacade
+{
+ private static final Logger log = LoggerFactory.getLogger(MockWalletFacade.class);
+
+ private BigInteger balance;
+
+ public MockWalletFacade()
+ {
+ balance = new BigInteger("100000000");
+ }
+
+ @Override
+ public BigInteger getBalance()
+ {
+ return balance;
+ }
+
+ @Override
+ public boolean pay(BigInteger satoshisToPay, String destinationAddress)
+ {
+ if (getBalance().subtract(satoshisToPay).longValue() > 0)
+ {
+ log.info("Pay " + satoshisToPay.toString() + " Satoshis to " + destinationAddress);
+ return true;
+ }
+ else
+ {
+ log.warn("Not enough funds in wallet for paying " + satoshisToPay.toString() + " Satoshis.");
+ return false;
+ }
+
+ }
+
+ @Override
+ public KeyPair createNewAddress()
+ {
+ //MOCK
+ return new KeyPair(UUID.randomUUID().toString(), UUID.randomUUID().toString());
+ }
+}
diff --git a/src/main/java/io/bitsquare/crypto/ICryptoFacade.java b/src/main/java/io/bitsquare/crypto/ICryptoFacade.java
new file mode 100644
index 0000000000..53e1c1cbad
--- /dev/null
+++ b/src/main/java/io/bitsquare/crypto/ICryptoFacade.java
@@ -0,0 +1,6 @@
+package io.bitsquare.crypto;
+
+public interface ICryptoFacade
+{
+ String sign(String data);
+}
diff --git a/src/main/java/io/bitsquare/crypto/MockCryptoFacade.java b/src/main/java/io/bitsquare/crypto/MockCryptoFacade.java
new file mode 100644
index 0000000000..32642b0bd0
--- /dev/null
+++ b/src/main/java/io/bitsquare/crypto/MockCryptoFacade.java
@@ -0,0 +1,16 @@
+package io.bitsquare.crypto;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MockCryptoFacade implements ICryptoFacade
+{
+ private static final Logger log = LoggerFactory.getLogger(MockCryptoFacade.class);
+
+ @Override
+ public String sign(String data)
+ {
+ log.info("sign data: " + data);
+ return "signed contract data";
+ }
+}
diff --git a/src/main/java/io/bitsquare/di/BitSquareModule.java b/src/main/java/io/bitsquare/di/BitSquareModule.java
new file mode 100644
index 0000000000..4190481eb1
--- /dev/null
+++ b/src/main/java/io/bitsquare/di/BitSquareModule.java
@@ -0,0 +1,44 @@
+package io.bitsquare.di;
+
+
+import com.google.inject.AbstractModule;
+import io.bitsquare.btc.BlockChainFacade;
+import io.bitsquare.btc.IWalletFacade;
+import io.bitsquare.btc.MockWalletFacade;
+import io.bitsquare.crypto.ICryptoFacade;
+import io.bitsquare.crypto.MockCryptoFacade;
+import io.bitsquare.msg.IMessageFacade;
+import io.bitsquare.msg.MessageFacade;
+import io.bitsquare.settings.OrderBookFilterSettings;
+import io.bitsquare.settings.Settings;
+import io.bitsquare.setup.ISetup;
+import io.bitsquare.setup.MockSetup;
+import io.bitsquare.storage.IStorage;
+import io.bitsquare.storage.SimpleStorage;
+import io.bitsquare.trade.TradingFacade;
+import io.bitsquare.trade.orderbook.IOrderBook;
+import io.bitsquare.trade.orderbook.MockOrderBook;
+import io.bitsquare.trade.orderbook.OrderBookFilter;
+import io.bitsquare.user.User;
+
+public class BitSquareModule extends AbstractModule
+{
+ @Override
+ protected void configure()
+ {
+ bind(ISetup.class).to(MockSetup.class).asEagerSingleton();
+ bind(User.class).asEagerSingleton();
+ bind(IOrderBook.class).to(MockOrderBook.class).asEagerSingleton();
+ bind(IStorage.class).to(SimpleStorage.class).asEagerSingleton();
+ bind(Settings.class).asEagerSingleton();
+ bind(OrderBookFilter.class).asEagerSingleton();
+ bind(OrderBookFilterSettings.class).asEagerSingleton();
+
+ bind(ICryptoFacade.class).to(MockCryptoFacade.class).asEagerSingleton();
+ bind(IWalletFacade.class).to(MockWalletFacade.class).asEagerSingleton();
+ bind(BlockChainFacade.class).asEagerSingleton();
+ bind(IMessageFacade.class).to(MessageFacade.class).asEagerSingleton();
+
+ bind(TradingFacade.class).asEagerSingleton();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/di/GuiceControllerFactory.java b/src/main/java/io/bitsquare/di/GuiceControllerFactory.java
new file mode 100644
index 0000000000..be18d87f14
--- /dev/null
+++ b/src/main/java/io/bitsquare/di/GuiceControllerFactory.java
@@ -0,0 +1,29 @@
+package io.bitsquare.di;
+
+import com.google.inject.Injector;
+import javafx.util.Callback;
+
+/**
+ * A JavaFX controller factory for constructing controllers via Guice DI. To
+ * install this in the {@link javafx.fxml.FXMLLoader}, pass it as a parameter to
+ * {@link javafx.fxml.FXMLLoader#setControllerFactory(Callback)}.
+ *
+ * Once set, make sure you do not use the static methods on
+ * {@link javafx.fxml.FXMLLoader} when creating your JavaFX node.
+ */
+public class GuiceControllerFactory implements Callback, Object>
+{
+
+ private Injector injector;
+
+ public GuiceControllerFactory(Injector injector)
+ {
+ this.injector = injector;
+ }
+
+ @Override
+ public Object call(Class> aClass)
+ {
+ return injector.getInstance(aClass);
+ }
+}
diff --git a/src/main/java/io/bitsquare/di/GuiceFXMLLoader.java b/src/main/java/io/bitsquare/di/GuiceFXMLLoader.java
new file mode 100644
index 0000000000..6c80ccae9e
--- /dev/null
+++ b/src/main/java/io/bitsquare/di/GuiceFXMLLoader.java
@@ -0,0 +1,28 @@
+package io.bitsquare.di;
+
+import com.google.inject.Injector;
+import javafx.fxml.FXMLLoader;
+
+/**
+ * Guice support for fxml controllers
+ */
+public class GuiceFXMLLoader extends FXMLLoader
+{
+
+ private static Injector injector = null;
+
+ public GuiceFXMLLoader()
+ {
+ if (GuiceFXMLLoader.injector != null)
+ setControllerFactory(new GuiceControllerFactory(GuiceFXMLLoader.injector));
+ }
+
+ public GuiceFXMLLoader(Injector injector)
+ {
+ if (GuiceFXMLLoader.injector == null)
+ {
+ GuiceFXMLLoader.injector = injector;
+ setControllerFactory(new GuiceControllerFactory(GuiceFXMLLoader.injector));
+ }
+ }
+}
diff --git a/src/main/java/io/bitsquare/gui/IChildController.java b/src/main/java/io/bitsquare/gui/IChildController.java
new file mode 100644
index 0000000000..a55e5bc062
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/IChildController.java
@@ -0,0 +1,6 @@
+package io.bitsquare.gui;
+
+public interface IChildController
+{
+ void setNavigationController(INavigationController navigationController);
+}
diff --git a/src/main/java/io/bitsquare/gui/INavigationController.java b/src/main/java/io/bitsquare/gui/INavigationController.java
new file mode 100644
index 0000000000..5f47d087b6
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/INavigationController.java
@@ -0,0 +1,19 @@
+package io.bitsquare.gui;
+
+public interface INavigationController
+{
+
+ public static final String HOME = "/io/bitsquare/gui/home/HomeView.fxml";
+ public static final String TRADE = "/io/bitsquare/gui/trade/TradeView.fxml";
+ public static final String ORDERS = "/io/bitsquare/gui/orders/OrdersView.fxml";
+ public static final String FUNDS = "/io/bitsquare/gui/funds/FundsView.fxml";
+ public static final String MSG = "/io/bitsquare/gui/msg/MsgView.fxml";
+ public static final String HISTORY = "/io/bitsquare/gui/history/HistoryView.fxml";
+ public static final String SETTINGS = "/io/bitsquare/gui/settings/SettingsView.fxml";
+
+ public static final String TRADE__ORDER_BOOK = "/io/bitsquare/gui/trade/orderbook/OrderBookView.fxml";
+ public static final String TRADE__PROCESS = "/io/bitsquare/gui/trade/tradeprocess/TradeProcessView.fxml";
+ public static final String TRADE__CREATE_OFFER = "/io/bitsquare/gui/trade/offer/CreateOfferView.fxml";
+
+ IChildController navigateToView(String fxmlView, String title);
+}
diff --git a/src/main/java/io/bitsquare/gui/MainController.java b/src/main/java/io/bitsquare/gui/MainController.java
new file mode 100644
index 0000000000..7125b4b684
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/MainController.java
@@ -0,0 +1,165 @@
+package io.bitsquare.gui;
+
+import com.google.inject.Inject;
+import io.bitsquare.BitSquare;
+import io.bitsquare.di.GuiceFXMLLoader;
+import io.bitsquare.gui.trade.TradeController;
+import io.bitsquare.gui.util.Icons;
+import io.bitsquare.settings.Settings;
+import io.bitsquare.trade.Direction;
+import io.bitsquare.trade.orderbook.OrderBookFilter;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.FXCollections;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.scene.Node;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.ToggleButton;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.VBox;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Currency;
+import java.util.ResourceBundle;
+
+public class MainController implements Initializable, INavigationController
+{
+ private Settings settings;
+ private OrderBookFilter orderBookFilter;
+ private IChildController childController;
+ private ToggleGroup toggleGroup;
+ private ToggleButton prevToggleButton;
+ private Image prevToggleButtonIcon;
+
+ @FXML
+ public Pane contentPane;
+ public HBox leftNavPane, rightNavPane;
+
+ @Inject
+ public MainController(Settings settings, OrderBookFilter orderBookFilter)
+ {
+ this.settings = settings;
+ this.orderBookFilter = orderBookFilter;
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle rb)
+ {
+ toggleGroup = new ToggleGroup();
+
+ ToggleButton homeButton = addNavButton(leftNavPane, "Overview", Icons.HOME, Icons.HOME, INavigationController.HOME);
+ ToggleButton buyButton = addNavButton(leftNavPane, "Buy BTC", Icons.NAV_BUY, Icons.NAV_BUY_ACTIVE, INavigationController.TRADE, Direction.BUY);
+ ToggleButton sellButton = addNavButton(leftNavPane, "Sell BTC", Icons.NAV_SELL, Icons.NAV_SELL_ACTIVE, INavigationController.TRADE, Direction.SELL);
+ addNavButton(leftNavPane, "Orders", Icons.ORDERS, Icons.ORDERS, INavigationController.ORDERS);
+ addNavButton(leftNavPane, "History", Icons.HISTORY, Icons.HISTORY, INavigationController.HISTORY);
+ addNavButton(leftNavPane, "Funds", Icons.FUNDS, Icons.FUNDS, INavigationController.FUNDS);
+ addNavButton(leftNavPane, "Message", Icons.MSG, Icons.MSG, INavigationController.MSG);
+ addCurrencyComboBox();
+ addNavButton(rightNavPane, "Settings", Icons.SETTINGS, Icons.SETTINGS, INavigationController.SETTINGS);
+
+
+ sellButton.fire();
+ //homeButton.fire();
+ }
+
+ @Override
+ public IChildController navigateToView(String fxmlView, String title)
+ {
+ FXMLLoader loader = new GuiceFXMLLoader();
+ try
+ {
+ Node view = loader.load(BitSquare.class.getResourceAsStream(fxmlView));
+ contentPane.getChildren().setAll(view);
+ childController = loader.getController();
+ childController.setNavigationController(this);
+ return childController;
+ } catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ return null;
+
+ }
+
+ public IChildController navigateToView(String fxmlView, Direction direction)
+ {
+ childController = navigateToView(fxmlView, direction == Direction.BUY ? "Orderbook Buy" : "Orderbook Sell");
+ if (childController instanceof TradeController && direction != null)
+ {
+ ((TradeController) childController).setDirection(direction);
+ }
+ return childController;
+ }
+
+ private ToggleButton addNavButton(Pane parent, String title, String iconId, String iconIdActivated, String navTarget)
+ {
+ return addNavButton(parent, title, iconId, iconIdActivated, navTarget, null);
+ }
+
+ private ToggleButton addNavButton(Pane parent, String title, String iconId, String iconIdActivated, String navTarget, Direction direction)
+ {
+ VBox vBox = new VBox();
+ ToggleButton toggleButton = new ToggleButton("", Icons.getIconImageView(iconId));
+ toggleButton.setPrefWidth(50);
+ toggleButton.setToggleGroup(toggleGroup);
+ Label titleLabel = new Label(title);
+ titleLabel.setPrefWidth(50);
+
+ toggleButton.setId("nav-button");
+ titleLabel.setId("nav-button-label");
+
+ vBox.getChildren().setAll(toggleButton, titleLabel);
+ parent.getChildren().add(vBox);
+
+ toggleButton.setOnAction(e -> {
+
+
+ if (prevToggleButton != null)
+ {
+ ((ImageView) (prevToggleButton.getGraphic())).setImage(prevToggleButtonIcon);
+ }
+ prevToggleButtonIcon = ((ImageView) (toggleButton.getGraphic())).getImage();
+ ((ImageView) (toggleButton.getGraphic())).setImage(Icons.getIconImage(iconIdActivated));
+
+ if (childController instanceof TradeController && direction != null)
+ {
+ ((TradeController) childController).setDirection(direction);
+ }
+ else
+ navigateToView(navTarget, direction);
+
+ prevToggleButton = toggleButton;
+
+ });
+ return toggleButton;
+ }
+
+ private void addCurrencyComboBox()
+ {
+ Pane holder = new Pane();
+ ComboBox currencyComboBox = new ComboBox(FXCollections.observableArrayList(settings.getAllCurrencies()));
+ currencyComboBox.setLayoutY(10);
+ currencyComboBox.setId("nav-currency-combobox");
+ currencyComboBox.setValue(Settings.getCurrency());
+
+ currencyComboBox.valueProperty().addListener(new ChangeListener()
+ {
+ @Override
+ public void changed(ObservableValue ov, Currency oldValue, Currency newValue)
+ {
+ orderBookFilter.setCurrency(newValue);
+ settings.setCurrency(newValue);
+ }
+ });
+ holder.getChildren().add(currencyComboBox);
+ rightNavPane.getChildren().add(holder);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/gui/MainView.fxml b/src/main/java/io/bitsquare/gui/MainView.fxml
new file mode 100644
index 0000000000..f3b9269c29
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/MainView.fxml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/io/bitsquare/gui/components/BuySellSwitch.java b/src/main/java/io/bitsquare/gui/components/BuySellSwitch.java
new file mode 100644
index 0000000000..770be531f0
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/components/BuySellSwitch.java
@@ -0,0 +1,37 @@
+package io.bitsquare.gui.components;
+
+import javafx.event.ActionEvent;
+import javafx.scene.control.ToggleButton;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+
+public class BuySellSwitch extends ToggleButton
+{
+
+ private static Image buyIcon = new Image(BuySellSwitch.class.getResourceAsStream("/images/buy.png"));
+ private static Image sellIcon = new Image(BuySellSwitch.class.getResourceAsStream("/images/sell.png"));
+
+ public BuySellSwitch(String label)
+ {
+ super(label);
+
+ ImageView iconImageView = new ImageView(buyIcon);
+ //setClip(iconImageView);
+ setGraphic(iconImageView);
+ addEventHandler(ActionEvent.ACTION, e -> {
+ if (isSelected())
+ {
+
+ setText("SELL");
+ iconImageView.setImage(sellIcon);
+ }
+ else
+ {
+ setText("BUY");
+ iconImageView.setImage(buyIcon);
+ }
+ });
+ }
+
+
+}
diff --git a/src/main/java/io/bitsquare/gui/components/HSpacer.java b/src/main/java/io/bitsquare/gui/components/HSpacer.java
new file mode 100644
index 0000000000..479e51002e
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/components/HSpacer.java
@@ -0,0 +1,23 @@
+package io.bitsquare.gui.components;
+
+
+import javafx.scene.layout.Pane;
+
+public class HSpacer extends Pane
+{
+ public HSpacer()
+ {
+ }
+
+ public HSpacer(double width)
+ {
+ setPrefWidth(width);
+ }
+
+ @Override
+ protected double computePrefWidth(double width)
+ {
+ return getPrefWidth();
+ }
+}
+
diff --git a/src/main/java/io/bitsquare/gui/components/NoFocusScrollPane.java b/src/main/java/io/bitsquare/gui/components/NoFocusScrollPane.java
new file mode 100644
index 0000000000..b32695d188
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/components/NoFocusScrollPane.java
@@ -0,0 +1,11 @@
+package io.bitsquare.gui.components;
+
+import javafx.scene.control.ScrollPane;
+
+public class NoFocusScrollPane extends ScrollPane
+{
+ public void requestFocus()
+ {
+ // prevent focus
+ }
+}
diff --git a/src/main/java/io/bitsquare/gui/components/PTableColumn.java b/src/main/java/io/bitsquare/gui/components/PTableColumn.java
new file mode 100644
index 0000000000..163c41f0a9
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/components/PTableColumn.java
@@ -0,0 +1,66 @@
+package io.bitsquare.gui.components;
+
+import javafx.beans.property.DoubleProperty;
+import javafx.beans.property.SimpleDoubleProperty;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.scene.control.TableView;
+
+/**
+ * This class allows to specify a percentage for the width of the column of a
+ * TableView.
+ *
+ * @author twasyl
+ */
+public class PTableColumn extends javafx.scene.control.TableColumn
+{
+
+ private final DoubleProperty percentageWidth = new SimpleDoubleProperty(0);
+
+ public PTableColumn()
+ {
+ tableViewProperty().addListener(new ChangeListener>()
+ {
+
+ @Override
+ public void changed(ObservableValue extends TableView> ov, TableView t, TableView t1)
+ {
+ if (PTableColumn.this.prefWidthProperty().isBound())
+ {
+ PTableColumn.this.prefWidthProperty().unbind();
+ }
+ if (percentageWidth.get() != 0)
+ {
+ PTableColumn.this.prefWidthProperty().bind(t1.widthProperty().multiply(percentageWidth));
+ }
+ else
+ {
+ double tempPercentageWidthLeft = 1;
+ for (int i = 0; i < t1.getColumns().size(); i++)
+ {
+ tempPercentageWidthLeft -= ((PTableColumn) t1.getColumns().get(i)).getPercentageWidth();
+ }
+ PTableColumn.this.prefWidthProperty().bind(t1.widthProperty().multiply(tempPercentageWidthLeft));
+ }
+ }
+ });
+ }
+
+ public final DoubleProperty percentageWidthProperty()
+ {
+ return percentageWidth;
+ }
+
+ public final double getPercentageWidth()
+ {
+ return this.percentageWidthProperty().get();
+ }
+
+ public final void setPercentageWidth(double value) throws IllegalArgumentException
+ {
+ if (value >= 0 && value <= 1)
+ this.percentageWidthProperty().set(value);
+ else
+ throw new IllegalArgumentException(String.format("The provided percentage width is not between 0.0 and 1.0. Value is: %1$s", value));
+ }
+}
diff --git a/src/main/java/io/bitsquare/gui/components/VSpacer.java b/src/main/java/io/bitsquare/gui/components/VSpacer.java
new file mode 100644
index 0000000000..d0dc7f339a
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/components/VSpacer.java
@@ -0,0 +1,23 @@
+package io.bitsquare.gui.components;
+
+
+import javafx.scene.layout.Pane;
+
+public class VSpacer extends Pane
+{
+ public VSpacer()
+ {
+ }
+
+ public VSpacer(double height)
+ {
+ setPrefHeight(height);
+ }
+
+ @Override
+ protected double computePrefHeight(double width)
+ {
+ return getPrefHeight();
+ }
+}
+
diff --git a/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepBar.java b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepBar.java
new file mode 100644
index 0000000000..63ce9eae25
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepBar.java
@@ -0,0 +1,32 @@
+package io.bitsquare.gui.components.processbar;
+
+import javafx.scene.control.Control;
+import javafx.scene.control.Skin;
+
+import java.util.List;
+
+public class ProcessStepBar extends Control
+{
+ private List processStepItems;
+
+ public ProcessStepBar(List processStepItems)
+ {
+ this.processStepItems = processStepItems;
+ }
+
+ @Override
+ protected Skin> createDefaultSkin()
+ {
+ return new ProcessStepBarSkin<>(this);
+ }
+
+ List getProcessStepItems()
+ {
+ return processStepItems;
+ }
+
+ public void next()
+ {
+ ((ProcessStepBarSkin) getSkin()).next();
+ }
+}
diff --git a/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepBarSkin.java b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepBarSkin.java
new file mode 100644
index 0000000000..d89c7f63e4
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepBarSkin.java
@@ -0,0 +1,201 @@
+package io.bitsquare.gui.components.processbar;
+
+import com.sun.javafx.scene.control.behavior.BehaviorBase;
+import com.sun.javafx.scene.control.behavior.KeyBinding;
+import com.sun.javafx.scene.control.skin.BehaviorSkinBase;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.layout.Border;
+import javafx.scene.layout.BorderStroke;
+import javafx.scene.layout.BorderStrokeStyle;
+import javafx.scene.layout.BorderWidths;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.*;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+
+public class ProcessStepBarSkin extends BehaviorSkinBase, BehaviorBase>>
+{
+ LabelWithBorder currentLabelWithBorder;
+ LabelWithBorder prevLabelWithBorder;
+ final ProcessStepBar controller;
+ int index;
+ List labelWithBorders;
+
+ public ProcessStepBarSkin(final ProcessStepBar control)
+ {
+ super(control, new BehaviorBase<>(control, Collections.emptyList()));
+
+ controller = getSkinnable();
+
+ int i = 0;
+ labelWithBorders = new ArrayList<>();
+ int size = controller.getProcessStepItems().size();
+ for (Iterator iterator = controller.getProcessStepItems().iterator(); iterator.hasNext(); )
+ {
+ ProcessStepItem processStepItem = iterator.next();
+ LabelWithBorder labelWithBorder = new LabelWithBorder(processStepItem, i == 0, i == size - 1);
+ getChildren().add(labelWithBorder);
+ labelWithBorders.add(labelWithBorder);
+ if (i == 0)
+ currentLabelWithBorder = prevLabelWithBorder = labelWithBorder;
+
+ i++;
+ }
+
+ currentLabelWithBorder.select();
+ }
+
+ public void next()
+ {
+ index++;
+
+ prevLabelWithBorder.deSelect();
+ if (index < labelWithBorders.size())
+ {
+ currentLabelWithBorder = labelWithBorders.get(index);
+ currentLabelWithBorder.select();
+
+ prevLabelWithBorder = currentLabelWithBorder;
+ }
+ }
+
+ @Override
+ protected void layoutChildren(double x, double y, double width, double height)
+ {
+ double distance = 10;
+ double padding = 50;
+ for (int i = 0; i < getChildren().size(); i++)
+ {
+ Node node = getChildren().get(i);
+
+ double newWidth = snapSize(node.prefWidth(height)) + padding;
+ double newHeight = snapSize(node.prefHeight(-1) + 10);
+
+ if (i > 0)
+ x = snapPosition(x - ((LabelWithBorder) node).getArrowWidth());
+
+ x = snapPosition(x);
+ y = snapPosition(y);
+ node.resize(newWidth, newHeight);
+ node.relocate(x, y);
+ x += newWidth + distance;
+ }
+ }
+
+ public static class LabelWithBorder extends Label
+ {
+ private final double arrowWidth = 10;
+ private final double arrowHeight = 30;
+ private ProcessStepItem processStepItem;
+ private boolean isFirst;
+ private boolean isLast;
+ double borderWidth = 1;
+
+ public LabelWithBorder(ProcessStepItem processStepItem, boolean isFirst, boolean isLast)
+ {
+ super(processStepItem.getLabel());
+ this.processStepItem = processStepItem;
+
+ this.isFirst = isFirst;
+ this.isLast = isLast;
+
+ setAlignment(Pos.CENTER);
+ setTextFill(Color.GRAY);
+ setStyle("-fx-font-size: 14");
+
+ this.setShape(createButtonShape());
+
+ BorderStroke borderStroke = new BorderStroke(Color.LIGHTGRAY, BorderStrokeStyle.SOLID, null,
+ new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
+ this.setBorder(new Border(borderStroke));
+ }
+
+ public void select()
+ {
+ BorderStroke borderStroke = new BorderStroke(processStepItem.getColor(), BorderStrokeStyle.SOLID, null,
+ new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
+ this.setBorder(new Border(borderStroke));
+ setTextFill(processStepItem.getColor());
+ }
+
+ public void deSelect()
+ {
+ /*BorderStroke borderStroke = new BorderStroke(Color.GRAY, BorderStrokeStyle.SOLID, null,
+ new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY);
+ this.setBorder(new Border(borderStroke));
+ setTextFill(Color.GRAY); */
+ }
+
+
+ public double getArrowWidth()
+ {
+ return arrowWidth;
+ }
+
+ private Path createButtonShape()
+ {
+ // build the following shape (or home without left arrow)
+
+ // --------
+ // \ \
+ // / /
+ // --------
+ Path path = new Path();
+
+ // begin in the upper left corner
+ MoveTo e1 = new MoveTo(0, 0);
+ path.getElements().add(e1);
+
+ // draw a horizontal line that defines the width of the shape
+ HLineTo e2 = new HLineTo();
+ // bind the width of the shape to the width of the button
+ e2.xProperty().bind(this.widthProperty().subtract(arrowWidth));
+ path.getElements().add(e2);
+
+ if (!isLast)
+ {
+ // draw upper part of right arrow
+ LineTo e3 = new LineTo();
+ // the x endpoint of this line depends on the x property of line e2
+ e3.xProperty().bind(e2.xProperty().add(arrowWidth));
+ e3.setY(arrowHeight / 2.0);
+ path.getElements().add(e3);
+ }
+
+
+ // draw lower part of right arrow
+ LineTo e4 = new LineTo();
+ // the x endpoint of this line depends on the x property of line e2
+ e4.xProperty().bind(e2.xProperty());
+ e4.setY(arrowHeight);
+ path.getElements().add(e4);
+
+ // draw lower horizontal line
+ HLineTo e5 = new HLineTo(0);
+ path.getElements().add(e5);
+
+ if (!isFirst)
+ {
+ LineTo e6 = new LineTo(arrowWidth, arrowHeight / 2.0);
+ path.getElements().add(e6);
+ }
+
+ // close path
+ ClosePath e7 = new ClosePath();
+ path.getElements().add(e7);
+ // this is a dummy color to fill the shape, it won't be visible
+ path.setFill(Color.BLACK);
+
+ return path;
+ }
+
+
+ }
+}
diff --git a/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepItem.java b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepItem.java
new file mode 100644
index 0000000000..a953f76c0d
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepItem.java
@@ -0,0 +1,42 @@
+package io.bitsquare.gui.components.processbar;
+
+import javafx.scene.paint.Paint;
+
+public class ProcessStepItem
+{
+ private String label;
+ private Paint color;
+ private boolean progressIndicator;
+
+ public ProcessStepItem(String label)
+ {
+ this(label, Paint.valueOf("#000000"), false);
+ }
+
+ public ProcessStepItem(String label, Paint color)
+ {
+ this(label, color, false);
+ }
+
+ public ProcessStepItem(String label, Paint color, boolean hasProgressIndicator)
+ {
+ this.label = label;
+ this.color = color;
+ this.progressIndicator = hasProgressIndicator;
+ }
+
+ public String getLabel()
+ {
+ return label;
+ }
+
+ public Paint getColor()
+ {
+ return color;
+ }
+
+ public boolean hasProgressIndicator()
+ {
+ return progressIndicator;
+ }
+}
diff --git a/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepsBuilder.java b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepsBuilder.java
new file mode 100644
index 0000000000..30503730c3
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepsBuilder.java
@@ -0,0 +1,84 @@
+package io.bitsquare.gui.components.processbar;
+
+import io.bitsquare.gui.util.Utils;
+import javafx.animation.AnimationTimer;
+import javafx.scene.control.Button;
+import javafx.scene.control.Control;
+import javafx.scene.control.ProgressIndicator;
+import javafx.scene.layout.Pane;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ProcessStepsBuilder
+{
+ protected int index = 0;
+ private Control previousControl;
+ private Pane controlHolder;
+ protected Object controller;
+ protected List processStepItems = new ArrayList();
+ protected ProcessStepBar processStepBar;
+
+ public void build(Pane processStepBarHolder, Pane controlHolder, Object controller)
+ {
+ this.controlHolder = controlHolder;
+ this.controller = controller;
+
+ fillProcessStepItems();
+
+ processStepBar = new ProcessStepBar(processStepItems);
+ processStepBar.relocate(10, 10);
+
+ processStepBarHolder.getChildren().add(processStepBar);
+
+ update();
+ }
+
+ public void next()
+ {
+ index++;
+ update();
+ processStepBar.next();
+ }
+
+ // template
+ protected void fillProcessStepItems()
+ {
+ // to be defined in subclasses
+ }
+
+ protected void update()
+ {
+ if (index < processStepItems.size())
+ {
+ ProcessStepItem processStepItem = processStepItems.get(index);
+ if (previousControl != null)
+ controlHolder.getChildren().remove(previousControl);
+
+ if (processStepItem.hasProgressIndicator())
+ {
+ final ProgressIndicator progressIndicator = new ProgressIndicator();
+ progressIndicator.setProgress(-1.0);
+ progressIndicator.setPrefSize(30.0, 30.0);
+ controlHolder.getChildren().add(progressIndicator);
+ previousControl = progressIndicator;
+
+ // TODO
+ // mock simulate network delay
+ Utils.setTimeout(100, (AnimationTimer animationTimer) -> {
+ next();
+ return null;
+ });
+ }
+ else
+ {
+ final Button button = new Button(processStepItem.getLabel());
+ button.setOnAction(e -> next());
+
+ controlHolder.getChildren().add(button);
+ previousControl = button;
+ }
+ }
+ }
+}
+
diff --git a/src/main/java/io/bitsquare/gui/funds/FundsController.java b/src/main/java/io/bitsquare/gui/funds/FundsController.java
new file mode 100644
index 0000000000..f693c94580
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/funds/FundsController.java
@@ -0,0 +1,26 @@
+package io.bitsquare.gui.funds;
+
+import io.bitsquare.gui.IChildController;
+import io.bitsquare.gui.INavigationController;
+import javafx.fxml.Initializable;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class FundsController implements Initializable, IChildController
+{
+ private INavigationController navigationController;
+
+ @Override
+ public void initialize(URL url, ResourceBundle rb)
+ {
+
+ }
+
+ @Override
+ public void setNavigationController(INavigationController navigationController)
+ {
+ this.navigationController = navigationController;
+ }
+}
+
diff --git a/src/main/java/io/bitsquare/gui/funds/FundsView.fxml b/src/main/java/io/bitsquare/gui/funds/FundsView.fxml
new file mode 100644
index 0000000000..72ce4696a6
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/funds/FundsView.fxml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/gui/global.css b/src/main/java/io/bitsquare/gui/global.css
new file mode 100644
index 0000000000..8c299a3f84
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/global.css
@@ -0,0 +1,109 @@
+#root-pane {
+ -fx-background-color: #dddddd;
+}
+
+#content-pane {
+ -fx-background-color: #f4f4f4;
+}
+
+/* main nav */
+
+#nav-button {
+ -fx-background-color: transparent;
+}
+
+#nav-button-label {
+ -fx-font-size: 10;
+ -fx-alignment: center;
+ -fx-padding: -10;
+}
+
+#nav-buy-button {
+ -fx-background-color: transparent;
+}
+
+#nav-buy-button-label {
+ -fx-font-size: 10;
+ -fx-alignment: center;
+ -fx-padding: -10;
+}
+
+#nav-sell-button {
+ -fx-background-color: transparent;
+}
+
+#nav-sell-button-label {
+ -fx-font-size: 10;
+ -fx-alignment: center;
+ -fx-padding: -10;
+}
+
+#nav-currency-combobox {
+}
+
+/* */
+
+#orderbook-table .table-cell {
+ -fx-alignment: center;
+}
+
+#orderbook-table .column-header .label {
+ -fx-alignment: center;
+}
+
+#orderbook-table .focus {
+ -fx-alignment: center;
+}
+
+#feedback-text {
+ -fx-font-size: 10;
+}
+
+
+/* forms */
+#form-header-text {
+ -fx-font-weight: bold;
+ -fx-font-size: 14;
+}
+
+#form-title {
+ -fx-font-weight: bold;
+}
+
+
+/* tabpane */
+.tab-pane .tab-label {
+ -fx-font-size: 15;
+}
+
+.tab-pane:focused {
+ -fx-background-color: transparent;
+}
+
+.tab-header-area:focused {
+ -fx-background-color: transparent;
+}
+
+.tab:focused {
+ -fx-background-color: transparent;
+}
+
+/* tableview */
+.table-view:focused {
+ -fx-background-color: transparent;
+}
+
+/* scrollpane */
+
+.scroll-pane {
+ -fx-background-insets: 0;
+ -fx-padding: 0;
+}
+
+.scroll-pane:focused {
+ -fx-background-insets: 0;
+}
+
+.scroll-pane .corner {
+ -fx-background-insets: 0;
+}
diff --git a/src/main/java/io/bitsquare/gui/history/HistoryController.java b/src/main/java/io/bitsquare/gui/history/HistoryController.java
new file mode 100644
index 0000000000..4943bfacc1
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/history/HistoryController.java
@@ -0,0 +1,28 @@
+package io.bitsquare.gui.history;
+
+import io.bitsquare.gui.IChildController;
+import io.bitsquare.gui.INavigationController;
+import javafx.fxml.Initializable;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class HistoryController implements Initializable, IChildController
+{
+
+ private INavigationController navigationController;
+
+ @Override
+ public void initialize(URL url, ResourceBundle rb)
+ {
+
+
+ }
+
+ @Override
+ public void setNavigationController(INavigationController navigationController)
+ {
+ this.navigationController = navigationController;
+ }
+}
+
diff --git a/src/main/java/io/bitsquare/gui/history/HistoryView.fxml b/src/main/java/io/bitsquare/gui/history/HistoryView.fxml
new file mode 100644
index 0000000000..0b9aaff1b3
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/history/HistoryView.fxml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/gui/home/HomeController.java b/src/main/java/io/bitsquare/gui/home/HomeController.java
new file mode 100644
index 0000000000..9ad52f01bd
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/home/HomeController.java
@@ -0,0 +1,32 @@
+package io.bitsquare.gui.home;
+
+import io.bitsquare.gui.IChildController;
+import io.bitsquare.gui.INavigationController;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.layout.Pane;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class HomeController implements Initializable, IChildController
+{
+ private INavigationController navigationController;
+
+ @FXML
+ public Pane rootContainer;
+
+ @Override
+ public void initialize(URL url, ResourceBundle rb)
+ {
+
+ }
+
+ @Override
+ public void setNavigationController(INavigationController navigationController)
+ {
+ this.navigationController = navigationController;
+ }
+
+}
+
diff --git a/src/main/java/io/bitsquare/gui/home/HomeView.fxml b/src/main/java/io/bitsquare/gui/home/HomeView.fxml
new file mode 100644
index 0000000000..90c0ea8209
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/home/HomeView.fxml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/gui/msg/MockDelay.java b/src/main/java/io/bitsquare/gui/msg/MockDelay.java
new file mode 100644
index 0000000000..5ca9ffee47
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/msg/MockDelay.java
@@ -0,0 +1,50 @@
+package io.bitsquare.gui.msg;
+
+
+import java.util.concurrent.*;
+
+public class MockDelay
+{
+ public String waitForMsg(String expectedMsg)
+ {
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future future = executor.submit(new Task(expectedMsg));
+ try
+ {
+ try
+ {
+ // max timeout 5 sec
+ return future.get(5, TimeUnit.SECONDS);
+ } catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ } catch (ExecutionException e)
+ {
+ e.printStackTrace();
+ }
+ } catch (TimeoutException e)
+ {
+ System.out.println("Terminated!");
+ }
+
+ executor.shutdownNow();
+ return null;
+ }
+}
+
+class Task implements Callable
+{
+ private String expectedMsg;
+
+ Task(String expectedMsg)
+ {
+ this.expectedMsg = expectedMsg;
+ }
+
+ @Override
+ public String call() throws Exception
+ {
+ Thread.sleep(1000); // 1 seconds pause
+ return expectedMsg;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/gui/msg/MsgController.java b/src/main/java/io/bitsquare/gui/msg/MsgController.java
new file mode 100644
index 0000000000..84a0af6993
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/msg/MsgController.java
@@ -0,0 +1,27 @@
+package io.bitsquare.gui.msg;
+
+import io.bitsquare.gui.IChildController;
+import io.bitsquare.gui.INavigationController;
+import javafx.fxml.Initializable;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class MsgController implements Initializable, IChildController
+{
+ private INavigationController navigationController;
+
+ @Override
+ public void initialize(URL url, ResourceBundle rb)
+ {
+
+ }
+
+ @Override
+ public void setNavigationController(INavigationController navigationController)
+ {
+ this.navigationController = navigationController;
+ }
+
+}
+
diff --git a/src/main/java/io/bitsquare/gui/msg/MsgView.fxml b/src/main/java/io/bitsquare/gui/msg/MsgView.fxml
new file mode 100644
index 0000000000..e226640953
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/msg/MsgView.fxml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/gui/orders/OrdersController.java b/src/main/java/io/bitsquare/gui/orders/OrdersController.java
new file mode 100644
index 0000000000..9e6898df3a
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/orders/OrdersController.java
@@ -0,0 +1,30 @@
+package io.bitsquare.gui.orders;
+
+import io.bitsquare.gui.IChildController;
+import io.bitsquare.gui.INavigationController;
+import javafx.fxml.Initializable;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class OrdersController implements Initializable, IChildController
+{
+
+
+ private INavigationController navigationController;
+
+ @Override
+ public void initialize(URL url, ResourceBundle rb)
+ {
+
+
+ }
+
+ @Override
+ public void setNavigationController(INavigationController navigationController)
+ {
+ this.navigationController = navigationController;
+ }
+
+}
+
diff --git a/src/main/java/io/bitsquare/gui/orders/OrdersView.fxml b/src/main/java/io/bitsquare/gui/orders/OrdersView.fxml
new file mode 100644
index 0000000000..7f975defbf
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/orders/OrdersView.fxml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/gui/settings/SettingsController.java b/src/main/java/io/bitsquare/gui/settings/SettingsController.java
new file mode 100644
index 0000000000..fde025b2f7
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/settings/SettingsController.java
@@ -0,0 +1,30 @@
+package io.bitsquare.gui.settings;
+
+import io.bitsquare.gui.IChildController;
+import io.bitsquare.gui.INavigationController;
+import javafx.fxml.Initializable;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class SettingsController implements Initializable, IChildController
+{
+
+
+ private INavigationController navigationController;
+
+ @Override
+ public void initialize(URL url, ResourceBundle rb)
+ {
+
+
+ }
+
+ @Override
+ public void setNavigationController(INavigationController navigationController)
+ {
+ this.navigationController = navigationController;
+ }
+
+}
+
diff --git a/src/main/java/io/bitsquare/gui/settings/SettingsView.fxml b/src/main/java/io/bitsquare/gui/settings/SettingsView.fxml
new file mode 100644
index 0000000000..3666574c98
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/settings/SettingsView.fxml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/gui/trade/TradeController.java b/src/main/java/io/bitsquare/gui/trade/TradeController.java
new file mode 100644
index 0000000000..3a9b6966af
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/trade/TradeController.java
@@ -0,0 +1,89 @@
+package io.bitsquare.gui.trade;
+
+import io.bitsquare.BitSquare;
+import io.bitsquare.di.GuiceFXMLLoader;
+import io.bitsquare.gui.IChildController;
+import io.bitsquare.gui.INavigationController;
+import io.bitsquare.gui.trade.orderbook.OrderBookController;
+import io.bitsquare.trade.Direction;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.scene.control.Tab;
+import javafx.scene.control.TabPane;
+import javafx.scene.layout.Pane;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class TradeController implements Initializable, INavigationController, IChildController
+{
+ @FXML
+ private TabPane tabPane;
+
+ private IChildController childController;
+ private boolean orderbookCreated;
+ private INavigationController navigationController;
+ private OrderBookController orderBookController;
+
+ @Override
+ public IChildController navigateToView(String fxmlView, String title)
+ {
+ if (fxmlView.equals(INavigationController.TRADE__ORDER_BOOK) && orderbookCreated)
+ {
+ tabPane.getSelectionModel().select(0);
+ return null;
+ }
+
+ FXMLLoader loader = new GuiceFXMLLoader();
+ try
+ {
+ Pane view = loader.load(BitSquare.class.getResourceAsStream(fxmlView));
+ childController = loader.getController();
+ childController.setNavigationController(this);
+
+ if (childController instanceof OrderBookController)
+ orderBookController = (OrderBookController) childController;
+
+ Tab tab = new Tab(title);
+ tab.setContent(view);
+ tabPane.getTabs().add(tab);
+
+ if (fxmlView.equals(INavigationController.TRADE__ORDER_BOOK))
+ {
+ tab.setClosable(false);
+ orderbookCreated = true;
+ }
+
+ tabPane.getSelectionModel().select(tabPane.getTabs().size() - 1);
+
+ return childController;
+ } catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle rb)
+ {
+ navigateToView(INavigationController.TRADE__ORDER_BOOK, "Orderbook");
+ }
+
+ @Override
+ public void setNavigationController(INavigationController navigationController)
+ {
+
+ this.navigationController = navigationController;
+ }
+
+ public void setDirection(Direction direction)
+ {
+ tabPane.getSelectionModel().select(0);
+ orderBookController.setDirection(direction);
+ }
+
+}
+
diff --git a/src/main/java/io/bitsquare/gui/trade/TradeView.fxml b/src/main/java/io/bitsquare/gui/trade/TradeView.fxml
new file mode 100644
index 0000000000..47c670d0fa
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/trade/TradeView.fxml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/gui/trade/offer/CreateOfferController.java b/src/main/java/io/bitsquare/gui/trade/offer/CreateOfferController.java
new file mode 100644
index 0000000000..c75333f7e7
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/trade/offer/CreateOfferController.java
@@ -0,0 +1,271 @@
+package io.bitsquare.gui.trade.offer;
+
+import com.google.inject.Inject;
+import io.bitsquare.gui.IChildController;
+import io.bitsquare.gui.INavigationController;
+import io.bitsquare.gui.util.Converter;
+import io.bitsquare.gui.util.Formatter;
+import io.bitsquare.settings.OrderBookFilterSettings;
+import io.bitsquare.settings.Settings;
+import io.bitsquare.trade.Direction;
+import io.bitsquare.trade.Offer;
+import io.bitsquare.trade.OfferConstraints;
+import io.bitsquare.trade.TradingFacade;
+import io.bitsquare.trade.orderbook.MockOrderBook;
+import io.bitsquare.trade.orderbook.OrderBookFilter;
+import io.bitsquare.user.User;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.*;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.Pane;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Currency;
+import java.util.ResourceBundle;
+import java.util.UUID;
+
+public class CreateOfferController implements Initializable, IChildController
+{
+ private static final Logger log = LoggerFactory.getLogger(CreateOfferController.class);
+
+ private INavigationController navigationController;
+ private TradingFacade tradingFacade;
+ private OrderBookFilterSettings orderBookFilterSettings;
+ private Settings settings;
+ private User user;
+ private double filterPaneItemOffset;
+ private Direction direction;
+
+ @FXML
+ public AnchorPane holderPane;
+ @FXML
+ public Pane detailsPane;
+
+ @FXML
+ public Label buyLabel;
+ @FXML
+ public TextField volume;
+ @FXML
+ public ImageView directionImageView;
+
+ @FXML
+ public TextField amount;
+ @FXML
+ public TextField price;
+ @FXML
+ public TextField minAmount;
+ @FXML
+ public Button placeOfferButton;
+
+ @Inject
+ public CreateOfferController(TradingFacade tradingFacade, OrderBookFilterSettings orderBookFilterSettings, Settings settings, User user)
+ {
+ this.tradingFacade = tradingFacade;
+ this.orderBookFilterSettings = orderBookFilterSettings;
+ this.settings = settings;
+ this.user = user;
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle rb)
+ {
+ createFilterPane();
+
+ amount.textProperty().addListener(new ChangeListener()
+ {
+ @Override
+ public void changed(ObservableValue extends String> observable, String oldValue, String newValue)
+ {
+ setVolume();
+ }
+ });
+
+ price.textProperty().addListener(new ChangeListener()
+ {
+ @Override
+ public void changed(ObservableValue extends String> observable, String oldValue, String newValue)
+ {
+ setVolume();
+ }
+ });
+
+ placeOfferButton.setOnAction(e -> {
+ // TODO not impl yet. use mocks
+ OfferConstraints offerConstraints = new MockOrderBook(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);
+ tradingFacade.placeNewOffer(offer);
+
+ TabPane tabPane = ((TabPane) (holderPane.getParent().getParent()));
+ tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem());
+
+ navigationController.navigateToView(INavigationController.TRADE__ORDER_BOOK, "Orderbook");
+ });
+ }
+
+ @Override
+ public void setNavigationController(INavigationController navigationController)
+ {
+ this.navigationController = navigationController;
+ }
+
+ public void setOrderBookFilter(OrderBookFilter orderBookFilter)
+ {
+ direction = orderBookFilter.getDirection();
+ amount.setText(Formatter.formatPrice(orderBookFilter.getAmount()));
+ minAmount.setText(Formatter.formatPrice(orderBookFilter.getAmount()));
+ price.setText(Formatter.formatPrice(orderBookFilter.getPrice()));
+
+ configDirection();
+ }
+
+ private void configDirection()
+ {
+ String iconPath;
+ String buyLabelText;
+ if (direction == Direction.BUY)
+ {
+ iconPath = "/images/buy.png";
+ buyLabelText = "BUY";
+ }
+ else
+ {
+ iconPath = "/images/sell.png";
+ buyLabelText = "SELL";
+ }
+ Image icon = new Image(getClass().getResourceAsStream(iconPath));
+ directionImageView.setImage(icon);
+ buyLabel.setText(buyLabelText);
+ }
+
+ private void createFilterPane()
+ {
+ filterPaneItemOffset = 30;
+
+ ArrayList currencies = orderBookFilterSettings.getCurrencies();
+ Currency currency = orderBookFilterSettings.getCurrency();
+ ComboBox currencyComboBox = createCurrencyItem("Currency: ", currency, currencies);
+ currencyComboBox.valueProperty().addListener(new ChangeListener()
+ {
+ @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 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 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));
+ }
+
+
+}
+
diff --git a/src/main/java/io/bitsquare/gui/trade/offer/CreateOfferView.fxml b/src/main/java/io/bitsquare/gui/trade/offer/CreateOfferView.fxml
new file mode 100644
index 0000000000..e3c739201f
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/trade/offer/CreateOfferView.fxml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookController.java b/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookController.java
new file mode 100644
index 0000000000..62f30c45d4
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookController.java
@@ -0,0 +1,242 @@
+package io.bitsquare.gui.trade.orderbook;
+
+import com.google.inject.Inject;
+import io.bitsquare.gui.IChildController;
+import io.bitsquare.gui.INavigationController;
+import io.bitsquare.gui.trade.offer.CreateOfferController;
+import io.bitsquare.gui.trade.tradeprocess.TradeProcessController;
+import io.bitsquare.gui.util.Converter;
+import io.bitsquare.gui.util.Formatter;
+import io.bitsquare.gui.util.Icons;
+import io.bitsquare.settings.Settings;
+import io.bitsquare.trade.Direction;
+import io.bitsquare.trade.orderbook.IOrderBook;
+import io.bitsquare.trade.orderbook.MockOrderBook;
+import io.bitsquare.trade.orderbook.OrderBookFilter;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.Button;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.TextField;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+
+import java.net.URL;
+import java.text.DecimalFormat;
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.ResourceBundle;
+
+public class OrderBookController implements Initializable, IChildController
+{
+ private INavigationController navigationController;
+ private IOrderBook orderBook;
+ private Settings settings;
+
+ private OrderBookListItem selectedOrderBookListItem;
+ private final OrderBookFilter orderBookFilter;
+
+ private Button createOfferButton;
+ private Image buyIcon = Icons.getIconImage(Icons.BUY);
+ private Image sellIcon = Icons.getIconImage(Icons.SELL);
+
+ @FXML
+ public AnchorPane holderPane;
+ @FXML
+ public HBox topHBox;
+ @FXML
+ private Button tradeButton;
+ @FXML
+ public TextField volume, amount, price;
+ @FXML
+ public Pane filterPane;
+ @FXML
+ public TableView orderBookTable;
+ @FXML
+ public TableColumn priceColumn, amountColumn, volumeColumn;
+ @FXML
+ private ImageView tradeButtonImageView;
+
+ @Inject
+ public OrderBookController(IOrderBook orderBook, OrderBookFilter orderBookFilter, Settings settings)
+ {
+ this.orderBook = orderBook;
+ this.orderBookFilter = orderBookFilter;
+ this.settings = settings;
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle rb)
+ {
+ orderBookFilter.getCurrencyProperty().addListener(new ChangeListener()
+ {
+ @Override
+ public void changed(ObservableValue extends String> observable, String oldValue, String newValue)
+ {
+ updateOfferList();
+ }
+ });
+
+ createFilterPane();
+
+ updateOfferList();
+
+ amount.textProperty().addListener(new ChangeListener()
+ {
+ @Override
+ public void changed(ObservableValue extends String> observable, String oldValue, String newValue)
+ {
+ orderBookFilter.setAmount(textInputToNumber(oldValue, newValue));
+ updateOfferList();
+ updateVolume();
+ }
+ });
+
+ price.textProperty().addListener(new ChangeListener()
+ {
+ @Override
+ public void changed(ObservableValue extends String> observable, String oldValue, String newValue)
+ {
+ orderBookFilter.setPrice(textInputToNumber(oldValue, newValue));
+ updateOfferList();
+ updateVolume();
+ }
+ });
+
+ orderBookTable.getSelectionModel().selectedItemProperty().addListener((observableValue, oldValue, newValue) -> {
+ selectedOrderBookListItem = orderBookTable.getSelectionModel().getSelectedItem();
+ tradeButton.setDisable(selectedOrderBookListItem == null);
+ });
+
+ tradeButton.setOnAction(e -> openTradeTab(selectedOrderBookListItem));
+ tradeButton.setDisable(true);
+ tradeButton.setDefaultButton(true);
+ }
+
+ @Override
+ public void setNavigationController(INavigationController navigationController)
+ {
+ this.navigationController = navigationController;
+ }
+
+ public void setDirection(Direction direction)
+ {
+ orderBookTable.getSelectionModel().clearSelection();
+ tradeButton.setDisable(true);
+ price.setText("");
+
+ String title;
+ Image icon;
+ if (direction == Direction.SELL)
+ {
+ title = "SELL";
+ icon = sellIcon;
+ }
+ else
+ {
+ title = "BUY";
+ icon = buyIcon;
+ }
+ tradeButton.setText(title);
+ tradeButtonImageView.setImage(icon);
+ orderBookFilter.setDirection(direction);
+
+ updateOfferList();
+ }
+
+ private void openTradeTab(OrderBookListItem orderBookListItem)
+ {
+ String title = orderBookListItem.getOffer().getDirection() == Direction.BUY ? "Trade: Sell Bitcoin" : "Trade: Buy Bitcoin";
+ TradeProcessController tradeProcessController = (TradeProcessController) navigationController.navigateToView(INavigationController.TRADE__PROCESS, title);
+
+ double requestedAmount = orderBookListItem.getOffer().getAmount();
+ if (!amount.getText().equals(""))
+ requestedAmount = Converter.convertToDouble(amount.getText());
+
+ tradeProcessController.initView(orderBookListItem.getOffer(), requestedAmount);
+ }
+
+ private void displayCreateOfferButton()
+ {
+ if (createOfferButton == null)
+ {
+ createOfferButton = new Button("Create new offer");
+ holderPane.setBottomAnchor(createOfferButton, 375.0);
+ holderPane.setLeftAnchor(createOfferButton, 200.0);
+ holderPane.getChildren().add(createOfferButton);
+
+ createOfferButton.setOnAction(e -> {
+ IChildController nextController = navigationController.navigateToView(INavigationController.TRADE__CREATE_OFFER, "Create offer");
+ ((CreateOfferController) nextController).setOrderBookFilter(orderBookFilter);
+ });
+ }
+ createOfferButton.setVisible(true);
+
+ holderPane.setBottomAnchor(orderBookTable, 410.0);
+ }
+
+ private void updateOfferList()
+ {
+ ObservableList offers = orderBook.getFilteredList(orderBookFilter);
+ orderBookTable.setItems(offers);
+ orderBookTable.getSortOrder().add(priceColumn);
+ priceColumn.setSortType((orderBookFilter.getDirection() == Direction.BUY) ? TableColumn.SortType.ASCENDING : TableColumn.SortType.DESCENDING);
+
+ if (offers.size() == 0)
+ {
+ displayCreateOfferButton();
+ }
+ else if (createOfferButton != null)
+ {
+ createOfferButton.setVisible(false);
+ holderPane.setBottomAnchor(orderBookTable, 10.0);
+ }
+ }
+
+ private void createFilterPane()
+ {
+ MockOrderBook mockOrderBook = new MockOrderBook(settings);
+ orderBookFilter.setOfferConstraints(mockOrderBook.getRandomOfferConstraints());
+
+ OrderBookFilterTextItemBuilder.build(filterPane, "Bank transfer types: ", orderBookFilter.getOfferConstraints().getBankTransferTypes(), settings.getAllBankTransferTypes());
+ OrderBookFilterTextItemBuilder.build(filterPane, "Countries: ", orderBookFilter.getOfferConstraints().getCountries(), settings.getAllCountries());
+ OrderBookFilterTextItemBuilder.build(filterPane, "Languages: ", orderBookFilter.getOfferConstraints().getLanguages(), settings.getAllLanguages());
+ OrderBookFilterTextItemBuilder.build(filterPane, "Collateral: ", Arrays.asList(String.valueOf(orderBookFilter.getOfferConstraints().getCollateral())), settings.getAllCollaterals());
+ OrderBookFilterTextItemBuilder.build(filterPane, "Arbitrator: ", Arrays.asList(orderBookFilter.getOfferConstraints().getArbitrator()), settings.getAllArbitrators());
+ }
+
+ private double textInputToNumber(String oldValue, String newValue)
+ {
+ //TODO use regex.... or custom textfield component
+ double d = 0.0;
+ if (!newValue.equals(""))
+ {
+ try
+ {
+ DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Settings.getLocale());
+ d = decimalFormat.parse(newValue).doubleValue();
+ } catch (ParseException e)
+ {
+ amount.setText(oldValue);
+ d = Converter.convertToDouble(oldValue);
+ }
+ }
+ return d;
+ }
+
+ private void updateVolume()
+ {
+ double a = textInputToNumber(amount.getText(), amount.getText());
+ double p = textInputToNumber(price.getText(), price.getText());
+ volume.setText(Formatter.formatPrice(a * p));
+ }
+
+}
+
diff --git a/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookFilterTextItemBuilder.java b/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookFilterTextItemBuilder.java
new file mode 100644
index 0000000000..ddc1cee4e6
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookFilterTextItemBuilder.java
@@ -0,0 +1,134 @@
+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 values, List 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 openValues = new ArrayList<>(allValues);
+ openValues.removeAll(values);
+ ObservableList 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()
+ {
+ @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 iterator = values.iterator();
+ for (Iterator 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 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);
+ }
+}
diff --git a/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookListItem.java b/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookListItem.java
new file mode 100644
index 0000000000..829e0f45ba
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookListItem.java
@@ -0,0 +1,49 @@
+package io.bitsquare.gui.trade.orderbook;
+
+import io.bitsquare.gui.util.Formatter;
+import io.bitsquare.trade.Offer;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.beans.property.StringProperty;
+
+/**
+ * Wrapper for observable properties used by orderbook table view
+ */
+public class OrderBookListItem
+{
+ private final StringProperty price = new SimpleStringProperty();
+ private final StringProperty amount = new SimpleStringProperty();
+ private final StringProperty volume = new SimpleStringProperty();
+
+ private Offer offer;
+
+
+ public OrderBookListItem(Offer offer)
+ {
+ this.offer = offer;
+
+ this.price.set(Formatter.formatPrice(offer.getPrice()));
+ this.amount.set(Formatter.formatAmountWithMinAmount(offer.getAmount(), offer.getMinAmount()));
+ this.volume.set(Formatter.formatVolumeWithMinVolume(offer.getVolume(), offer.getMinVolume()));
+ }
+
+ public Offer getOffer()
+ {
+ return offer;
+ }
+
+ // called form table columns
+ public final StringProperty priceProperty()
+ {
+ return this.price;
+ }
+
+ public final StringProperty amountProperty()
+ {
+ return this.amount;
+ }
+
+ public final StringProperty volumeProperty()
+ {
+ return this.volume;
+ }
+}
diff --git a/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookView.fxml b/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookView.fxml
new file mode 100644
index 0000000000..05375319fb
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookView.fxml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/io/bitsquare/gui/trade/tradeprocess/TradeProcessController.java b/src/main/java/io/bitsquare/gui/trade/tradeprocess/TradeProcessController.java
new file mode 100644
index 0000000000..2cfc006c73
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/trade/tradeprocess/TradeProcessController.java
@@ -0,0 +1,436 @@
+package io.bitsquare.gui.trade.tradeprocess;
+
+import com.google.inject.Inject;
+import io.bitsquare.btc.BtcFormatter;
+import io.bitsquare.btc.Fees;
+import io.bitsquare.gui.IChildController;
+import io.bitsquare.gui.INavigationController;
+import io.bitsquare.gui.components.VSpacer;
+import io.bitsquare.gui.components.processbar.ProcessStepBar;
+import io.bitsquare.gui.components.processbar.ProcessStepItem;
+import io.bitsquare.gui.util.Colors;
+import io.bitsquare.gui.util.Converter;
+import io.bitsquare.gui.util.Formatter;
+import io.bitsquare.gui.util.Utils;
+import io.bitsquare.trade.*;
+import io.bitsquare.user.User;
+import javafx.animation.AnimationTimer;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.geometry.Insets;
+import javafx.scene.control.*;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.VBox;
+import org.controlsfx.dialog.Dialogs;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ResourceBundle;
+
+public class TradeProcessController implements Initializable, IChildController
+{
+ private TradingFacade tradingFacade;
+ private Offer offer;
+ private Trade trade;
+ private Contract contract;
+
+ private INavigationController navigationController;
+ private List processStepItems = new ArrayList();
+ private double requestedAmount;
+
+ private VBox vBox;
+ private TitledPane offerDetailsTitlePane, contractTitlePane;
+ private ProcessStepBar processStepBar;
+ private Button nextButton;
+ private TextField amountTextField;
+ private Label offererPubKeyLabel, offererAccountPrimaryID, offererAccountSecondaryIDLabel,
+ offererAccountHolderNameLabel, feedbackLabel, infoLabel, totalLabel, volumeLabel, totalToPayLabel,
+ totalToReceiveLabel, collateralLabel1, collateralLabel2, amountLabel;
+ private Pane progressPane;
+ private ProgressBar progressBar;
+ private ProgressIndicator progressIndicator;
+
+
+ @FXML
+ public AnchorPane rootContainer;
+
+ @Inject
+ public TradeProcessController(TradingFacade tradingFacade)
+ {
+ this.tradingFacade = tradingFacade;
+ }
+
+ @Override
+ public void setNavigationController(INavigationController navigationController)
+ {
+ this.navigationController = navigationController;
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle rb)
+ {
+ }
+
+ public void initView(Offer offer, double requestedAmount)
+ {
+ this.offer = offer;
+ this.requestedAmount = requestedAmount;
+
+ trade = tradingFacade.createNewTrade(offer);
+ trade.setRequestedAmount(requestedAmount);
+ contract = tradingFacade.createNewContract(trade);
+
+ processStepItems.add(new ProcessStepItem(takerIsSelling() ? "Sell BTC" : "Buy BTC", Colors.BLUE));
+ processStepItems.add(new ProcessStepItem("Bank transfer", Colors.BLUE));
+ processStepItems.add(new ProcessStepItem("Completed", Colors.BLUE));
+ processStepBar = new ProcessStepBar(processStepItems);
+
+ buildStep1();
+ }
+
+ private void trade()
+ {
+ double requestedAmount = Converter.convertToDouble(amountTextField.getText());
+ if (requestedAmount <= offer.getAmount() && requestedAmount >= offer.getMinAmount())
+ {
+ amountTextField.setEditable(false);
+ trade.setRequestedAmount(requestedAmount);
+
+ vBox.getChildren().remove(nextButton);
+ AnchorPane.setTopAnchor(contractTitlePane, 350.0);
+
+ progressBar = new ProgressBar();
+ progressBar.setProgress(0.0);
+ progressBar.setPrefWidth(200);
+ progressBar.relocate(10, 10);
+
+ progressIndicator = new ProgressIndicator();
+ progressIndicator.setProgress(-1.0);
+ progressIndicator.setPrefSize(20, 20);
+ progressIndicator.relocate(220, 10);
+
+ feedbackLabel = new Label();
+ feedbackLabel.setPadding(new Insets(-10, 0, 0, 0));
+ feedbackLabel.setId("feedback-text");
+ feedbackLabel.relocate(10, 50);
+
+ progressPane = new Pane();
+ progressPane.getChildren().addAll(progressBar, progressIndicator, feedbackLabel);
+
+ vBox.getChildren().add(progressPane);
+
+ sendTakeOfferRequest();
+ }
+ else
+ {
+ Dialogs.create()
+ .title("Your input is not valid")
+ .message("The requested amount you entered is outside of the range of the offered amount.")
+ .nativeTitleBar()
+ .lightweight()
+ .showError();
+ }
+ }
+
+ // Payment Process
+ private void sendTakeOfferRequest()
+ {
+ tradingFacade.sendTakeOfferRequest(trade);
+ feedbackLabel.setText("Request take offer confirmation from peer.");
+ Utils.setTimeout(500, (AnimationTimer animationTimer) -> {
+ onTakeOfferRequestConfirmed();
+ progressBar.setProgress(1.0 / 3.0);
+ return null;
+ });
+ }
+
+ private void onTakeOfferRequestConfirmed()
+ {
+ tradingFacade.payOfferFee(trade);
+
+ feedbackLabel.setText("Request offer fee payment confirmation from peer.");
+ Utils.setTimeout(500, (AnimationTimer animationTimer) -> {
+ onOfferFeePaymentConfirmed();
+ progressBar.setProgress(2.0 / 3.0);
+ return null;
+ });
+ }
+
+ private void onOfferFeePaymentConfirmed()
+ {
+ tradingFacade.requestOffererDetailData();
+ feedbackLabel.setText("Request detail data from peer.");
+ Utils.setTimeout(500, (AnimationTimer animationTimer) -> {
+ onUserDetailsReceived();
+ progressBar.setProgress(1.0);
+ return null;
+ });
+ }
+
+ private void onUserDetailsReceived()
+ {
+ tradingFacade.signContract(contract);
+ tradingFacade.payToDepositTx(trade);
+
+ buildWaitBankTransfer();
+ }
+
+ private void buildWaitBankTransfer()
+ {
+ processStepBar.next();
+
+ vBox.getChildren().remove(progressPane);
+ vBox.getChildren().remove(offerDetailsTitlePane);
+ vBox.getChildren().remove(nextButton);
+ rootContainer.getChildren().remove(contractTitlePane);
+
+ infoLabel = new Label("Wait for Bank transfer.");
+ vBox.getChildren().addAll(infoLabel);
+
+ Utils.setTimeout(2000, (AnimationTimer animationTimer) -> {
+ onBankTransferInited();
+ return null;
+ });
+ }
+
+ private void onBankTransferInited()
+ {
+ infoLabel.setText("Bank transfer has been inited.\nCheck your bank account and continue when you have received the money.\n");
+ nextButton.setText("Money received on Bank account");
+ nextButton.setOnAction(e -> releaseBTC());
+ vBox.getChildren().add(nextButton);
+ }
+
+ private void releaseBTC()
+ {
+ processStepBar.next();
+ tradingFacade.releaseBTC(trade);
+
+ vBox.getChildren().remove(infoLabel);
+
+ nextButton.setText("Close");
+ nextButton.setOnAction(e -> close());
+
+ GridPane summaryGridPane = new GridPane();
+ int row = 0;
+ summaryGridPane.setVgap(5);
+ summaryGridPane.setHgap(5);
+ summaryGridPane.setPadding(new Insets(5, 5, 5, 5));
+
+ addLabel(summaryGridPane, "You have payed:", getTotalToPay(), ++row);
+ addLabel(summaryGridPane, "You have received:\n ", getTotalToReceive(), ++row);
+
+ TitledPane summaryTitlePane = new TitledPane("Trade summary:", summaryGridPane);
+ summaryTitlePane.setCollapsible(false);
+ vBox.getChildren().add(2, summaryTitlePane);
+ }
+
+ private void close()
+ {
+ TabPane tabPane = ((TabPane) (rootContainer.getParent().getParent()));
+ tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem());
+
+ navigationController.navigateToView(INavigationController.TRADE__ORDER_BOOK, "Orderbook");
+ }
+
+ private void buildStep1()
+ {
+ OfferConstraints offerConstraints = offer.getOfferConstraints();
+ User taker = contract.getTaker();
+ User offerer = contract.getOfferer();
+
+ GridPane offerDetailsGridPane = new GridPane();
+ int row = 0;
+ offerDetailsGridPane.setVgap(5);
+ offerDetailsGridPane.setHgap(5);
+ offerDetailsGridPane.setPadding(new Insets(5, 5, 5, 5));
+
+ amountTextField = addInputField(offerDetailsGridPane, "Amount (BTC):", Formatter.formatAmount(getAmount()), ++row);
+ amountTextField.textProperty().addListener(e -> {
+ setTotal();
+ setVolume();
+ setCollateral();
+ totalToPayLabel.setText(getTotalToPay());
+ totalToReceiveLabel.setText(getTotalToReceive());
+ amountLabel.setText(amountTextField.getText());
+
+ });
+
+ offerDetailsGridPane.add(new Label("(" + offer.getAmount() + "BTC - " + offer.getMinAmount() + "BTC)"), 2, row);
+
+ addLabel(offerDetailsGridPane, "Price:", Formatter.formatPriceWithCurrencyPair(offer.getPrice(), offer.getCurrency()), ++row);
+ totalLabel = addLabel(offerDetailsGridPane, "Total:", "", ++row);
+ setTotal();
+ collateralLabel1 = addLabel(offerDetailsGridPane, "Collateral:", Formatter.formatCollateral(offer.getOfferConstraints().getCollateral(), getAmount()), ++row);
+ addLabel(offerDetailsGridPane, "Offer fee:", Formatter.formatSatoshis(Fees.OFFER_CREATION_FEE, true), ++row);
+ addVSpacer(offerDetailsGridPane, ++row);
+ totalToPayLabel = addLabel(offerDetailsGridPane, "You pay:", getTotalToPay(), ++row);
+ totalToReceiveLabel = addLabel(offerDetailsGridPane, "You receive:\n ", getTotalToReceive(), ++row);
+
+ offerDetailsTitlePane = new TitledPane(takerIsSelling() ? "Sell Bitcoin" : "Buy Bitcoin", offerDetailsGridPane);
+ offerDetailsTitlePane.setCollapsible(false);
+
+ nextButton = new Button(processStepItems.get(0).getLabel());
+ nextButton.setDefaultButton(true);
+ nextButton.setOnAction(e -> trade());
+
+ GridPane contractGridPane = new GridPane();
+ contractGridPane.setVgap(5);
+ contractGridPane.setHgap(5);
+ contractGridPane.setPadding(new Insets(5, 5, 5, 5));
+ row = 0;
+ addHeaderLabel(contractGridPane, "Offer details:", row);
+ addLabel(contractGridPane, "Offer ID:", offer.getUid().toString(), ++row);
+ addLabel(contractGridPane, "Offer type:", Formatter.formatDirection((offer.getDirection() == Direction.BUY ? Direction.SELL : Direction.BUY), false), ++row);
+ amountLabel = addLabel(contractGridPane, "Amount:", Formatter.formatAmount(getAmount()), ++row);
+ volumeLabel = addLabel(contractGridPane, "Volume:", "", ++row);
+ setVolume();
+ addLabel(contractGridPane, "Price:", Formatter.formatPriceWithCurrencyPair(offer.getPrice(), offer.getCurrency()), ++row);
+ collateralLabel2 = addLabel(contractGridPane, "Collateral:", "", ++row);
+ setCollateral();
+ addLabel(contractGridPane, "Language:", Formatter.formatList(offerConstraints.getLanguages()), ++row);
+ addLabel(contractGridPane, "Arbitrator:", offerConstraints.getArbitrator(), ++row);
+ // addLabel(contractGridPane, "Identity verification:", Formatter.formatList(offerConstraints.getIdentityVerifications()), ++row);
+ addLabel(contractGridPane, "Bank transfer reference ID:", "Purchase xyz 01.04.2014", ++row);
+
+ addVSpacer(contractGridPane, ++row);
+ addHeaderLabel(contractGridPane, "Offerer data:", ++row);
+ addLabel(contractGridPane, "Account ID:", offerer.getAccountID(), ++row);
+ addLabel(contractGridPane, "Messaging ID:", offerer.getMessageID(), ++row);
+ addLabel(contractGridPane, "Country:", offerer.getCountry(), ++row);
+ offererPubKeyLabel = addLabel(contractGridPane, "Payment public key:", contract.getOffererPubKey(), ++row);
+ addLabel(contractGridPane, "Bank transfer type:", offerer.getBankDetails().getBankTransferType(), ++row);
+ offererAccountPrimaryID = addLabel(contractGridPane, "Bank account IBAN:", offerer.getBankDetails().getAccountPrimaryID(), ++row);
+ offererAccountSecondaryIDLabel = addLabel(contractGridPane, "Bank account BIC:", offerer.getBankDetails().getAccountSecondaryID(), ++row);
+ offererAccountHolderNameLabel = addLabel(contractGridPane, "Bank account holder:", offerer.getBankDetails().getAccountHolderName(), ++row);
+
+ addVSpacer(contractGridPane, ++row);
+ addHeaderLabel(contractGridPane, "Offer taker data:", ++row);
+ addLabel(contractGridPane, "Account ID:", taker.getAccountID(), ++row);
+ addLabel(contractGridPane, "Messaging ID:", taker.getMessageID(), ++row);
+ addLabel(contractGridPane, "Country:", taker.getCountry(), ++row);
+ addLabel(contractGridPane, "Payment public key:", contract.getTakerPubKey(), ++row);
+ addLabel(contractGridPane, "Bank transfer type:", taker.getBankDetails().getBankTransferType(), ++row);
+ addLabel(contractGridPane, "Bank account IBAN:", taker.getBankDetails().getAccountPrimaryID(), ++row);
+ addLabel(contractGridPane, "Bank account BIC:", taker.getBankDetails().getAccountSecondaryID(), ++row);
+ addLabel(contractGridPane, "Bank account holder:", taker.getBankDetails().getAccountHolderName(), ++row);
+
+ ScrollPane scrollPane = new ScrollPane();
+ scrollPane.setContent(contractGridPane);
+
+ contractTitlePane = new TitledPane("Contract", scrollPane);
+ contractTitlePane.setCollapsible(false);
+ AnchorPane.setLeftAnchor(contractTitlePane, 10.0);
+ AnchorPane.setRightAnchor(contractTitlePane, 10.0);
+ AnchorPane.setTopAnchor(contractTitlePane, 324.0);
+ AnchorPane.setBottomAnchor(contractTitlePane, 10.0);
+
+ vBox = new VBox();
+ AnchorPane.setLeftAnchor(vBox, 10.0);
+ AnchorPane.setRightAnchor(vBox, 10.0);
+ AnchorPane.setTopAnchor(vBox, 10.0);
+ vBox.setSpacing(10);
+
+ vBox.getChildren().addAll(processStepBar, new VSpacer(5), offerDetailsTitlePane, nextButton);
+ rootContainer.getChildren().addAll(vBox, contractTitlePane);
+ }
+
+ private Label addLabel(GridPane gridPane, String title, String value, int row)
+ {
+ gridPane.add(new Label(title), 0, row);
+ Label valueLabel = new Label(value);
+ gridPane.add(valueLabel, 1, row);
+ return valueLabel;
+ }
+
+ private void addHeaderLabel(GridPane gridPane, String title, int row)
+ {
+ Label headerLabel = new Label(title);
+ headerLabel.setId("form-header-text");
+ gridPane.add(headerLabel, 0, row);
+ }
+
+ private TextField addInputField(GridPane gridPane, String title, String value, int row)
+ {
+ gridPane.add(new Label(title), 0, row);
+ TextField textField = new TextField(value);
+ gridPane.add(textField, 1, row);
+ return textField;
+ }
+
+ private void addVSpacer(GridPane gridPane, int row)
+ {
+ gridPane.add(new VSpacer(10), 0, row);
+ }
+
+
+ private void setTotal()
+ {
+ totalLabel.setText(Formatter.formatVolume(getVolume()));
+ }
+
+ private void setVolume()
+ {
+ totalLabel.setText(Formatter.formatVolume(getVolume(), offer.getCurrency()));
+ }
+
+ private boolean takerIsSelling()
+ {
+ return offer.getDirection() == Direction.BUY;
+ }
+
+ private double getVolume()
+ {
+ return offer.getPrice() * Converter.convertToDouble(amountTextField.getText());
+ }
+
+ private double getAmount()
+ {
+ return requestedAmount > 0 ? requestedAmount : offer.getAmount();
+ }
+
+ private String getTotalToPay()
+ {
+ String result = "";
+ if (takerIsSelling())
+ {
+ double btcValue = Converter.convertToDouble(amountTextField.getText()) + BtcFormatter.satoshiToBTC(Fees.OFFER_CREATION_FEE) +
+ offer.getOfferConstraints().getCollateral() * Converter.convertToDouble(amountTextField.getText());
+ result = Formatter.formatAmount(btcValue, true, true);
+ }
+ else
+ {
+ double btcValue = BtcFormatter.satoshiToBTC(Fees.OFFER_CREATION_FEE) + offer.getOfferConstraints().getCollateral() * Converter.convertToDouble(amountTextField.getText());
+ result = Formatter.formatAmount(btcValue, true, true) + "\n" + Formatter.formatVolume(getVolume(), offer.getCurrency());
+ }
+ return result;
+ }
+
+ private String getTotalToReceive()
+ {
+ String result = "";
+ if (takerIsSelling())
+ {
+ double btcValue = offer.getOfferConstraints().getCollateral() * Converter.convertToDouble(amountTextField.getText());
+ result = Formatter.formatAmount(btcValue, true, true) + "\n" + Formatter.formatVolume(getVolume(), offer.getCurrency());
+ }
+ else
+ {
+ double btcValue = Converter.convertToDouble(amountTextField.getText()) +
+ offer.getOfferConstraints().getCollateral() * Converter.convertToDouble(amountTextField.getText());
+ result = Formatter.formatAmount(btcValue, true, true);
+ }
+ return result;
+ }
+
+ public void setCollateral()
+ {
+ String value = Formatter.formatCollateral(offer.getOfferConstraints().getCollateral(), Converter.convertToDouble(amountTextField.getText()));
+ collateralLabel1.setText(value);
+ collateralLabel2.setText(value);
+ }
+}
+
diff --git a/src/main/java/io/bitsquare/gui/trade/tradeprocess/TradeProcessView.fxml b/src/main/java/io/bitsquare/gui/trade/tradeprocess/TradeProcessView.fxml
new file mode 100644
index 0000000000..33d69e1f0c
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/trade/tradeprocess/TradeProcessView.fxml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/gui/util/Colors.java b/src/main/java/io/bitsquare/gui/util/Colors.java
new file mode 100644
index 0000000000..3d9a98caf7
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/util/Colors.java
@@ -0,0 +1,13 @@
+package io.bitsquare.gui.util;
+
+import javafx.scene.paint.Color;
+import javafx.scene.paint.Paint;
+
+public class Colors
+{
+ public static final Paint YELLOW = Color.valueOf("#edc035");
+ public static final Paint BLUE = Color.valueOf("#0096c9");
+ public static final Paint LIGHT_GREY = Color.valueOf("#f4f4f4");
+ public static final Paint DARK_GREY = Color.valueOf("#333333");
+
+}
diff --git a/src/main/java/io/bitsquare/gui/util/Converter.java b/src/main/java/io/bitsquare/gui/util/Converter.java
new file mode 100644
index 0000000000..c83dc93dd0
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/util/Converter.java
@@ -0,0 +1,24 @@
+package io.bitsquare.gui.util;
+
+import io.bitsquare.settings.Settings;
+
+import java.text.DecimalFormat;
+import java.text.ParseException;
+
+public class Converter
+{
+ public static double convertToDouble(String input)
+ {
+ try
+ {
+ DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Settings.getLocale());
+ return decimalFormat.parse(input).doubleValue();
+ } catch (ParseException e)
+ {
+ //e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ return 0.0;
+ }
+
+
+}
diff --git a/src/main/java/io/bitsquare/gui/util/Formatter.java b/src/main/java/io/bitsquare/gui/util/Formatter.java
new file mode 100644
index 0000000000..35890c6b89
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/util/Formatter.java
@@ -0,0 +1,126 @@
+package io.bitsquare.gui.util;
+
+import io.bitsquare.btc.BtcFormatter;
+import io.bitsquare.settings.Settings;
+import io.bitsquare.trade.Direction;
+
+import java.math.BigInteger;
+import java.text.DecimalFormat;
+import java.util.Currency;
+import java.util.List;
+
+public class Formatter
+{
+
+
+ public static String formatPrice(double price)
+ {
+ return formatDouble(price);
+ }
+
+ public static String formatPriceWithCurrencyPair(double price, Currency currency)
+ {
+ return formatDouble(price) + " " + currency.toString() + "/BTC";
+ }
+
+ public static String formatAmount(double amount, boolean useBTC, boolean exact)
+ {
+ return formatDouble(amount, (exact ? 4 : 2)) + (useBTC ? " BTC" : "");
+ }
+
+ public static String formatAmount(double amount, boolean useBTC)
+ {
+ return formatAmount(amount, useBTC, false);
+ }
+
+ public static String formatAmount(double amount)
+ {
+ return formatAmount(amount, false);
+ }
+
+ public static String formatAmountWithMinAmount(double amount, double minAmount, boolean useBTC)
+ {
+ if (useBTC)
+ return formatDouble(amount) + " BTC (" + formatDouble(minAmount) + " BTC)";
+ else
+ return formatDouble(amount) + " (" + formatDouble(minAmount) + ")";
+ }
+
+ public static String formatAmountWithMinAmount(double amount, double minAmount)
+ {
+ return formatAmountWithMinAmount(amount, minAmount, false);
+ }
+
+ public static String formatVolume(double volume)
+ {
+ return formatDouble(volume);
+ }
+
+ public static String formatVolume(double volume, Currency currency)
+ {
+ return formatDouble(volume) + " " + currency.toString();
+ }
+
+ public static String formatVolumeWithMinVolume(double volume, double minVolume, Currency currency)
+ {
+ return formatDouble(volume) + " " + currency.toString() + " (" + formatDouble(minVolume) + " " + currency.toString() + ")";
+ }
+
+ public static String formatVolumeWithMinVolume(double volume, double minVolume)
+ {
+ return formatDouble(volume) + " (" + formatDouble(minVolume) + ")";
+ }
+
+ public static String formatCollateral(double collateral, double amount)
+ {
+ return formatPercent(collateral) + " (" + formatDouble(collateral * amount, 4) + " BTC)";
+ }
+
+ public static String formatDirection(Direction direction, boolean allUpperCase)
+ {
+ String result = (direction == Direction.BUY) ? "Buy" : "Sell";
+ if (allUpperCase)
+ result = result.toUpperCase();
+ return result;
+ }
+
+ public static String formatList(List list)
+ {
+ String s = list.toString();
+ return s.substring(1, s.length() - 1);
+ }
+
+ public static String formatSatoshis(BigInteger satoshis, boolean useBTC)
+ {
+ if (useBTC)
+ return formatDouble(BtcFormatter.satoshiToBTC(satoshis), 4) + " BTC";
+ else
+ return formatDouble(BtcFormatter.satoshiToBTC(satoshis), 4);
+ }
+
+ public static String formatDouble(double value)
+ {
+ return formatDouble(value, 2);
+ }
+
+ public static String formatDouble(double value, int fractionDigits)
+ {
+ DecimalFormat decimalFormat = getDecimalFormat(fractionDigits);
+ return decimalFormat.format(value);
+ }
+
+ public static DecimalFormat getDecimalFormat(int fractionDigits)
+ {
+ DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Settings.getLocale());
+ decimalFormat.setMinimumFractionDigits(fractionDigits);
+ decimalFormat.setMaximumFractionDigits(fractionDigits);
+ decimalFormat.setGroupingUsed(false);
+ return decimalFormat;
+ }
+
+ private static String formatPercent(double value)
+ {
+ return value * 100 + "%";
+ }
+
+}
diff --git a/src/main/java/io/bitsquare/gui/util/Icons.java b/src/main/java/io/bitsquare/gui/util/Icons.java
new file mode 100644
index 0000000000..109ed64cb0
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/util/Icons.java
@@ -0,0 +1,33 @@
+package io.bitsquare.gui.util;
+
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+
+public class Icons
+{
+ public static final String HOME = "/images/home.png";
+ public static final String NAV_BUY = "/images/nav_buy.png";
+ public static final String NAV_BUY_ACTIVE = "/images/nav_buy_active.png";
+ public static final String NAV_SELL = "/images/nav_sell.png";
+ public static final String NAV_SELL_ACTIVE = "/images/nav_sell_active.png";
+ public static final String ORDERS = "/images/orders.png";
+ public static final String HISTORY = "/images/history.png";
+ public static final String FUNDS = "/images/funds.png";
+ public static final String MSG = "/images/msg.png";
+ public static final String SETTINGS = "/images/settings.png";
+
+ public static final String BUY = "/images/buy.png";
+ public static final String SELL = "/images/sell.png";
+ public static final String REMOVE = "/images/remove_minus_9.png";
+ public static final String ADD = "/images/list.png";
+
+ public static Image getIconImage(String iconName)
+ {
+ return new Image(Icons.class.getResourceAsStream(iconName));
+ }
+
+ public static ImageView getIconImageView(String iconName)
+ {
+ return new ImageView(new Image(Icons.class.getResourceAsStream(iconName)));
+ }
+}
diff --git a/src/main/java/io/bitsquare/gui/util/Loc.java b/src/main/java/io/bitsquare/gui/util/Loc.java
new file mode 100644
index 0000000000..9a342b96a8
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/util/Loc.java
@@ -0,0 +1,71 @@
+package io.bitsquare.gui.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+
+public class Loc
+{
+ public static String get(String key)
+ {
+ ResourceBundle bundle = ResourceBundle.getBundle("i18n.displayStrings", new UTF8Control());
+ return bundle.getString(key);
+ }
+
+ public static String get(String key, String... arguments)
+ {
+ String entry = ResourceBundle.getBundle("i18n.displayStrings", new UTF8Control()).getString(key);
+ return MessageFormat.format(entry, arguments);
+ }
+
+}
+
+class UTF8Control extends ResourceBundle.Control
+{
+
+ public ResourceBundle newBundle
+ (String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
+ throws IllegalAccessException, InstantiationException, IOException
+ {
+ // The below is a copy of the default implementation.
+ String bundleName = toBundleName(baseName, locale);
+ String resourceName = toResourceName(bundleName, "properties");
+ ResourceBundle bundle = null;
+ InputStream stream = null;
+ if (reload)
+ {
+ URL url = loader.getResource(resourceName);
+ if (url != null)
+ {
+ URLConnection connection = url.openConnection();
+ if (connection != null)
+ {
+ connection.setUseCaches(false);
+ stream = connection.getInputStream();
+ }
+ }
+ }
+ else
+ {
+ stream = loader.getResourceAsStream(resourceName);
+ }
+ if (stream != null)
+ {
+ try
+ {
+ // Only this line is changed to make it to read properties files as UTF-8.
+ bundle = new PropertyResourceBundle(new InputStreamReader(stream, "UTF-8"));
+ } finally
+ {
+ stream.close();
+ }
+ }
+ return bundle;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/gui/util/Utils.java b/src/main/java/io/bitsquare/gui/util/Utils.java
new file mode 100644
index 0000000000..19d650c309
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/util/Utils.java
@@ -0,0 +1,35 @@
+package io.bitsquare.gui.util;
+
+import javafx.animation.AnimationTimer;
+
+import java.util.function.Function;
+
+public class Utils
+{
+ /**
+ * @param delay in milliseconds
+ * @param callback
+ * @usage Utils.setTimeout(1000, (AnimationTimer animationTimer) -> {
+ * doSomething();
+ * return null;
+ * });
+ */
+ public static void setTimeout(int delay, Function callback)
+ {
+ long startTime = System.currentTimeMillis();
+ AnimationTimer animationTimer = new AnimationTimer()
+ {
+ @Override
+ public void handle(long arg0)
+ {
+ if (System.currentTimeMillis() > delay + startTime)
+ {
+ callback.apply(this);
+ this.stop();
+ }
+ }
+ };
+ animationTimer.start();
+ }
+}
+
diff --git a/src/main/java/io/bitsquare/msg/IMessageFacade.java b/src/main/java/io/bitsquare/msg/IMessageFacade.java
new file mode 100644
index 0000000000..f1f7909590
--- /dev/null
+++ b/src/main/java/io/bitsquare/msg/IMessageFacade.java
@@ -0,0 +1,13 @@
+package io.bitsquare.msg;
+
+/**
+ * Gateway to messaging
+ */
+public interface IMessageFacade
+{
+ void broadcast(Message message);
+
+ void send(Message message, String receiverMsgID);
+
+ void registerListener(String listenerPubKey);
+}
diff --git a/src/main/java/io/bitsquare/msg/Message.java b/src/main/java/io/bitsquare/msg/Message.java
new file mode 100644
index 0000000000..0bcb001ad7
--- /dev/null
+++ b/src/main/java/io/bitsquare/msg/Message.java
@@ -0,0 +1,60 @@
+package io.bitsquare.msg;
+
+import io.bitsquare.trade.Contract;
+import io.bitsquare.trade.Offer;
+import io.bitsquare.trade.Trade;
+import io.bitsquare.util.Utils;
+
+public class Message
+{
+ public final static String BROADCAST_NEW_OFFER = "BROADCAST_NEW_OFFER";
+ public final static String REQUEST_TAKE_OFFER = "REQUEST_TAKE_OFFER";
+ public final static String OFFER_ACCEPTED = "OFFER_ACCEPTED";
+ public final static String REQUEST_OFFER_FEE_PAYMENT_CONFIRM = "REQUEST_OFFER_FEE_PAYMENT_CONFIRM";
+ public final static String SEND_SIGNED_CONTRACT = "SEND_SIGNED_CONTRACT";
+
+ private String type;
+ private Object payload;
+
+
+ public Message(String type, String msg)
+ {
+ this.type = type;
+ this.payload = msg;
+ }
+
+ public Message(String type, Trade trade)
+ {
+ this.type = type;
+ this.payload = trade;
+ }
+
+ public Message(String type, Offer offer)
+ {
+ this.type = type;
+ this.payload = offer;
+ }
+
+ public Message(String type, Contract contract)
+ {
+ this.type = type;
+ this.payload = contract;
+ }
+
+ public String toString()
+ {
+ return type + ": " + Utils.convertToJson(payload);
+ }
+
+ public String getType()
+ {
+ return type;
+ }
+
+ public void setType(String type)
+ {
+ this.type = type;
+ }
+
+
+}
diff --git a/src/main/java/io/bitsquare/msg/MessageFacade.java b/src/main/java/io/bitsquare/msg/MessageFacade.java
new file mode 100644
index 0000000000..a473b7aa4a
--- /dev/null
+++ b/src/main/java/io/bitsquare/msg/MessageFacade.java
@@ -0,0 +1,28 @@
+package io.bitsquare.msg;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MessageFacade implements IMessageFacade
+{
+ private static final Logger log = LoggerFactory.getLogger(MessageFacade.class);
+
+ @Override
+ public void broadcast(Message message)
+ {
+ log.info(message.toString());
+ }
+
+ @Override
+ public void send(Message message, String receiverPubKey)
+ {
+ log.info(message.toString() + "/" + receiverPubKey);
+ }
+
+ @Override
+ public void registerListener(String listenerPubKey)
+ {
+ log.info(listenerPubKey);
+ }
+
+}
diff --git a/src/main/java/io/bitsquare/settings/OrderBookFilterSettings.java b/src/main/java/io/bitsquare/settings/OrderBookFilterSettings.java
new file mode 100644
index 0000000000..1a65715ce3
--- /dev/null
+++ b/src/main/java/io/bitsquare/settings/OrderBookFilterSettings.java
@@ -0,0 +1,89 @@
+package io.bitsquare.settings;
+
+import com.google.inject.Inject;
+import io.bitsquare.storage.IStorage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+public class OrderBookFilterSettings
+{
+ private static final Logger log = LoggerFactory.getLogger(OrderBookFilterSettings.class);
+
+ private IStorage storage;
+ private Currency currency;
+ private ArrayList currencies;
+
+ @Inject
+ public OrderBookFilterSettings(IStorage storage)
+ {
+ this.storage = storage;
+
+ currencies = getCurrencies();
+ currency = (Currency) storage.read("OrderBookFilterSettings.currency");
+ if (currency == null)
+ setCurrency(currencies.get(0));
+ }
+
+ public enum BankTransferTypes
+ {
+ SEPA, OKPAY, WIRE, PERFECT_MONEY, OTHER, ANY
+ }
+
+ public enum Arbitrators
+ {
+ PAYSTY, TLS_NOTARY, BIT_RATED, OTHER, ANY, NONE
+ }
+
+ public enum IdVerifications
+ {
+ PGP, BTC_OTC, OPEN_ID, NAME_COIN, NAME_ID, PASSPORT, SKYPE, FACEBOOK, GOOGLE_PLUS, TWITTER, OTHER, ANY, NONE
+ }
+
+
+ //TODO remove duplicated entries, insert separators
+ public ArrayList getCurrencies()
+ {
+ ArrayList 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 otherCurrenciesSet = Currency.getAvailableCurrencies();
+ ArrayList otherCurrenciesList = new ArrayList<>();
+ otherCurrenciesList.addAll(otherCurrenciesSet);
+ Collections.sort(otherCurrenciesList, new CurrencyComparator());
+
+ currencies.addAll(otherCurrenciesList);
+ return currencies;
+ }
+
+ public Currency getCurrency()
+ {
+ return currency;
+ }
+
+ public void setCurrency(Currency currency)
+ {
+ this.currency = currency;
+ storage.write("OrderBookFilterSettings.currency", currency);
+ }
+}
+
+class CurrencyComparator implements Comparator
+{
+ @Override
+ public int compare(Currency a, Currency b)
+ {
+ return a.getCurrencyCode().compareTo(b.getCurrencyCode());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/settings/Settings.java b/src/main/java/io/bitsquare/settings/Settings.java
new file mode 100644
index 0000000000..d1d51a223c
--- /dev/null
+++ b/src/main/java/io/bitsquare/settings/Settings.java
@@ -0,0 +1,187 @@
+package io.bitsquare.settings;
+
+import com.google.inject.Inject;
+import io.bitsquare.storage.IStorage;
+import io.bitsquare.trade.orderbook.OrderBookFilter;
+
+import java.util.ArrayList;
+import java.util.Currency;
+import java.util.Locale;
+
+public class Settings
+{
+ public static Locale locale = Locale.ENGLISH;
+ public static Currency currency = Currency.getInstance("USD");
+
+ private IStorage storage;
+ private OrderBookFilter orderBookFilter;
+
+ public static Locale getLocale()
+ {
+ return Settings.locale;
+ }
+
+ public static Currency getCurrency()
+ {
+ return Settings.currency;
+ }
+
+ @Inject
+ public Settings(IStorage storage, OrderBookFilter orderBookFilter)
+ {
+
+ this.orderBookFilter = orderBookFilter;
+ locale = Locale.ENGLISH;
+ currency = Currency.getInstance("USD");
+ this.storage = storage;
+
+ currency = (Currency) storage.read("Settings.currency");
+ if (currency == null)
+ currency = Currency.getInstance("USD");
+ }
+
+
+ //TODO remove duplicated entries, insert separators
+ public ArrayList getAllCurrencies()
+ {
+ ArrayList 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 otherCurrenciesSet = Currency.getAvailableCurrencies();
+ ArrayList otherCurrenciesList = new ArrayList<>();
+ otherCurrenciesList.addAll(otherCurrenciesSet);
+ Collections.sort(otherCurrenciesList, new CurrencyComparator());
+
+ currencies.addAll(otherCurrenciesList); */
+ return currencies;
+ }
+
+ public ArrayList getAllBankTransferTypes()
+ {
+ ArrayList bankTransferTypes = new ArrayList<>();
+ bankTransferTypes.add("SEPA");
+ bankTransferTypes.add("Wire");
+ bankTransferTypes.add("International");
+ bankTransferTypes.add("OKPay");
+ bankTransferTypes.add("Netteller");
+ bankTransferTypes.add("Perfect Money");
+ bankTransferTypes.add("Any");
+ return bankTransferTypes;
+ }
+
+ public ArrayList getAllCountries()
+ {
+ ArrayList bankTransferTypes = new ArrayList<>();
+ bankTransferTypes.add("USA");
+ bankTransferTypes.add("GB");
+ bankTransferTypes.add("DE");
+ bankTransferTypes.add("FR");
+ bankTransferTypes.add("ES");
+ bankTransferTypes.add("CH");
+ bankTransferTypes.add("RUS");
+ bankTransferTypes.add("AUS");
+ bankTransferTypes.add("CAN");
+ bankTransferTypes.add("AT");
+ return bankTransferTypes;
+ }
+ /*
+ public ArrayList getAllCountries()
+ {
+ ArrayList result = new ArrayList<>();
+ for (Locale locale : Locale.getAvailableLocales())
+ {
+ result.add(locale.getDisplayCountry());
+ }
+ return result;
+ } */
+
+ /*public ArrayList getAllLanguages()
+ {
+ ArrayList result = new ArrayList<>();
+ for (Locale locale : Locale.getAvailableLocales())
+ {
+ result.add(locale.getDisplayLanguage());
+ }
+
+ return result;
+ } */
+ public ArrayList getAllLanguages()
+ {
+ ArrayList bankTransferTypes = new ArrayList<>();
+ bankTransferTypes.add("English");
+ bankTransferTypes.add("Chinese");
+ bankTransferTypes.add("Spanish");
+ bankTransferTypes.add("Russian");
+ bankTransferTypes.add("French");
+ bankTransferTypes.add("Italian");
+ return bankTransferTypes;
+ }
+
+ public ArrayList getAllArbitrators()
+ {
+ ArrayList arbitrators = new ArrayList<>();
+ arbitrators.add("Paysty pool 1");
+ arbitrators.add("Paysty pool 2");
+ arbitrators.add("Paysty pool 3");
+ arbitrators.add("Paysty pool 4");
+ return arbitrators;
+ }
+
+ public ArrayList getAllIdentityVerifications()
+ {
+ ArrayList 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 getAllCollaterals()
+ {
+ ArrayList 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;
+ }
+
+}
diff --git a/src/main/java/io/bitsquare/setup/ISetup.java b/src/main/java/io/bitsquare/setup/ISetup.java
new file mode 100644
index 0000000000..3aa9f42e8d
--- /dev/null
+++ b/src/main/java/io/bitsquare/setup/ISetup.java
@@ -0,0 +1,6 @@
+package io.bitsquare.setup;
+
+public interface ISetup
+{
+ void applyPersistedData();
+}
diff --git a/src/main/java/io/bitsquare/setup/MockSetup.java b/src/main/java/io/bitsquare/setup/MockSetup.java
new file mode 100644
index 0000000000..879ac6aa92
--- /dev/null
+++ b/src/main/java/io/bitsquare/setup/MockSetup.java
@@ -0,0 +1,59 @@
+package io.bitsquare.setup;
+
+import com.google.inject.Inject;
+import io.bitsquare.settings.Settings;
+import io.bitsquare.storage.IStorage;
+import io.bitsquare.trade.Direction;
+import io.bitsquare.trade.orderbook.OrderBookFilter;
+import io.bitsquare.user.BankDetails;
+import io.bitsquare.user.User;
+
+import java.util.UUID;
+
+public class MockSetup implements ISetup
+{
+ private IStorage storage;
+ private User user;
+ private OrderBookFilter orderBookFilter;
+
+ @Inject
+ public MockSetup(IStorage storage, User user, OrderBookFilter orderBookFilter)
+ {
+ this.storage = storage;
+ this.user = user;
+ this.orderBookFilter = orderBookFilter;
+ }
+
+ @Override
+ public void applyPersistedData()
+ {
+ String accountID = (String) storage.read("User.accountID");
+ if (accountID == null)
+ {
+ storage.write("User.accountID", UUID.randomUUID().toString());
+ storage.write("User.messageID", UUID.randomUUID().toString());
+ storage.write("User.country", "ES");
+
+ storage.write("BankDetails.bankTransferType", "SEPA");
+ storage.write("BankDetails.accountPrimaryID", "IBAN_12312");
+ storage.write("BankDetails.accountSecondaryID", "BIC_123123");
+ storage.write("BankDetails.accountHolderName", "Bob Brown");
+ }
+
+ user.setAccountID((String) storage.read("User.accountID"));
+ user.setMessageID((String) storage.read("User.messageID"));
+ user.setCountry((String) storage.read("User.country"));
+ user.setBankDetails(new BankDetails((String) storage.read("BankDetails.bankTransferType"),
+ (String) storage.read("BankDetails.accountPrimaryID"),
+ (String) storage.read("BankDetails.accountSecondaryID"),
+ (String) storage.read("BankDetails.accountHolderName")));
+
+ // todo use persistence
+ orderBookFilter.setAmount(0.0);
+ orderBookFilter.setPrice(0.0);
+ orderBookFilter.setDirection(Direction.BUY);
+ orderBookFilter.setCurrency(Settings.getCurrency());
+
+
+ }
+}
diff --git a/src/main/java/io/bitsquare/storage/IStorage.java b/src/main/java/io/bitsquare/storage/IStorage.java
new file mode 100644
index 0000000000..0a3b354498
--- /dev/null
+++ b/src/main/java/io/bitsquare/storage/IStorage.java
@@ -0,0 +1,8 @@
+package io.bitsquare.storage;
+
+public interface IStorage
+{
+ void write(String key, Object value);
+
+ Object read(String key);
+}
diff --git a/src/main/java/io/bitsquare/storage/SimpleStorage.java b/src/main/java/io/bitsquare/storage/SimpleStorage.java
new file mode 100644
index 0000000000..b3f0066159
--- /dev/null
+++ b/src/main/java/io/bitsquare/storage/SimpleStorage.java
@@ -0,0 +1,95 @@
+package io.bitsquare.storage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Simple storage solution for serialized data
+ */
+public class SimpleStorage implements IStorage
+{
+ private static final Logger log = LoggerFactory.getLogger(SimpleStorage.class);
+
+ private final String preferencesFileName = "preferences.ser";
+ private final String storageFile;
+ private DataVO dataVO;
+
+ public SimpleStorage()
+ {
+ storageFile = SimpleStorage.class.getProtectionDomain().getCodeSource().getLocation().getFile() + "/" + preferencesFileName;
+
+ dataVO = readDataVO();
+ if (dataVO == null)
+ {
+ dataVO = new DataVO();
+ dataVO.dict = new HashMap();
+ writeDataVO(dataVO);
+ }
+ }
+
+ @Override
+ public void write(String key, Object value)
+ {
+ log.info("Write object with key = " + key + " / value = " + value);
+ dataVO.dict.put(key, value);
+ writeDataVO(dataVO);
+ }
+
+
+ @Override
+ public Object read(String key)
+ {
+ dataVO = readDataVO();
+ Object result = dataVO.dict.get(key);
+ log.info("Read object with key = " + key + " result = " + result);
+ return result;
+ }
+
+ private void writeDataVO(DataVO dataVO)
+ {
+ try
+ {
+ FileOutputStream fileOut = new FileOutputStream(storageFile);
+ ObjectOutputStream out = new ObjectOutputStream(fileOut);
+ out.writeObject(dataVO);
+ out.close();
+ fileOut.close();
+ } catch (IOException i)
+ {
+ i.printStackTrace();
+ }
+ }
+
+ private DataVO readDataVO()
+ {
+ DataVO dataVO = null;
+ File file = new File(storageFile);
+ if (file.exists())
+ {
+ try
+ {
+ FileInputStream fileIn = new FileInputStream(file);
+ ObjectInputStream in = new ObjectInputStream(fileIn);
+ dataVO = (DataVO) in.readObject();
+ in.close();
+ fileIn.close();
+ } catch (IOException i)
+ {
+ i.printStackTrace();
+ } catch (ClassNotFoundException c)
+ {
+ c.printStackTrace();
+ }
+ }
+ return dataVO;
+ }
+}
+
+class DataVO implements Serializable
+{
+ public Map dict;
+}
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/trade/Contract.java b/src/main/java/io/bitsquare/trade/Contract.java
new file mode 100644
index 0000000000..80613900af
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/Contract.java
@@ -0,0 +1,78 @@
+package io.bitsquare.trade;
+
+import io.bitsquare.user.User;
+
+import java.util.UUID;
+
+public class Contract
+{
+ private User taker;
+ private User offerer;
+ private String offererPubKey;
+ private Trade trade;
+ private String takerPubKey;
+
+
+ public Contract(Trade trade, String takerPubKey)
+ {
+ this.trade = trade;
+ this.takerPubKey = takerPubKey;
+ }
+
+ public UUID getUid()
+ {
+ return trade.getUid();
+ }
+
+ public void setTaker(User taker)
+ {
+ this.taker = taker;
+ }
+
+ public User getTaker()
+ {
+ return taker;
+ }
+
+ public User getOfferer()
+ {
+ return offerer;
+ }
+
+ public void setOfferer(User offerer)
+ {
+ this.offerer = offerer;
+ }
+
+
+ public String getTakerPubKey()
+ {
+ return takerPubKey;
+ }
+
+ public void setTakerPubKey(String takerPubKey)
+ {
+ this.takerPubKey = takerPubKey;
+ }
+
+ public String getOffererPubKey()
+ {
+ return offererPubKey;
+ }
+
+ public void setOffererPubKey(String offererPubKey)
+ {
+ this.offererPubKey = offererPubKey;
+ }
+
+
+ public Trade getTrade()
+ {
+ return trade;
+ }
+
+ public void setTrade(Trade trade)
+ {
+ this.trade = trade;
+ }
+}
diff --git a/src/main/java/io/bitsquare/trade/Direction.java b/src/main/java/io/bitsquare/trade/Direction.java
new file mode 100644
index 0000000000..ea77c8f4bd
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/Direction.java
@@ -0,0 +1,6 @@
+package io.bitsquare.trade;
+
+public enum Direction
+{
+ BUY, SELL
+}
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/trade/Offer.java b/src/main/java/io/bitsquare/trade/Offer.java
new file mode 100644
index 0000000000..f7afaa7ce7
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/Offer.java
@@ -0,0 +1,129 @@
+package io.bitsquare.trade;
+
+import io.bitsquare.user.User;
+
+import java.util.Currency;
+import java.util.UUID;
+
+public class Offer
+{
+ private UUID uid;
+ private double price;
+ private double amount;
+ private double minAmount;
+ private Direction direction;
+ private Currency currency;
+ private User offerer;
+ private OfferConstraints offerConstraints;
+
+ public Offer(UUID uid,
+ Direction direction,
+ double price,
+ double amount,
+ double minAmount,
+ Currency currency,
+ User offerer,
+ OfferConstraints offerConstraints)
+ {
+ this.uid = uid;
+ this.direction = direction;
+ this.price = price;
+ this.amount = amount;
+ this.minAmount = minAmount;
+ this.currency = currency;
+ this.offerer = offerer;
+ this.offerConstraints = offerConstraints;
+ }
+
+ public double getVolume()
+ {
+ return price * amount;
+ }
+
+ public double getMinVolume()
+ {
+ return price * minAmount;
+ }
+
+ public UUID getUid()
+ {
+ return uid;
+ }
+
+ 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;
+ }
+}
diff --git a/src/main/java/io/bitsquare/trade/OfferConstraints.java b/src/main/java/io/bitsquare/trade/OfferConstraints.java
new file mode 100644
index 0000000000..dea8a9700f
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/OfferConstraints.java
@@ -0,0 +1,58 @@
+package io.bitsquare.trade;
+
+import java.util.List;
+
+public class OfferConstraints
+{
+ private double collateral;
+ private List countries;
+ private List languages;
+ private List bankTransferTypes;
+ private String arbitrator;
+ private String identityVerification;
+
+ public OfferConstraints(List countries,
+ List languages,
+ double collateral,
+ List bankTransferTypes,
+ String arbitrator,
+ String identityVerification)
+ {
+ this.countries = countries;
+ this.languages = languages;
+ this.collateral = collateral;
+ this.bankTransferTypes = bankTransferTypes;
+ this.arbitrator = arbitrator;
+ this.identityVerification = identityVerification;
+ }
+
+ public double getCollateral()
+ {
+ return collateral;
+ }
+
+ public List getCountries()
+ {
+ return countries;
+ }
+
+ public List getLanguages()
+ {
+ return languages;
+ }
+
+ public List getBankTransferTypes()
+ {
+ return bankTransferTypes;
+ }
+
+ public String getArbitrator()
+ {
+ return arbitrator;
+ }
+
+ public String getIdentityVerification()
+ {
+ return identityVerification;
+ }
+}
diff --git a/src/main/java/io/bitsquare/trade/Trade.java b/src/main/java/io/bitsquare/trade/Trade.java
new file mode 100644
index 0000000000..8d9f57278c
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/Trade.java
@@ -0,0 +1,86 @@
+package io.bitsquare.trade;
+
+import java.util.UUID;
+
+public class Trade
+{
+ private Offer offer;
+ private boolean takeOfferRequested;
+ private boolean takeOfferAccepted;
+ private double requestedAmount;
+ private boolean takeOfferFeePayed;
+ private boolean takeOfferFeePaymentConfirmed;
+ private String jsonRepresentation;
+ private String signature;
+ private String takeOfferFeeTxID;
+
+ public Trade(Offer offer)
+ {
+ this.offer = offer;
+ }
+
+ public Offer getOffer()
+ {
+ return offer;
+ }
+
+ public UUID getUid()
+ {
+ return offer.getUid();
+ }
+
+ public void setJsonRepresentation(String jsonRepresentation)
+ {
+ this.jsonRepresentation = jsonRepresentation;
+ }
+
+ public void setSignature(String signature)
+ {
+ this.signature = signature;
+ }
+
+ public boolean isTakeOfferRequested()
+ {
+ return takeOfferRequested;
+ }
+
+ public void setTakeOfferRequested(boolean takeOfferRequested)
+ {
+ this.takeOfferRequested = takeOfferRequested;
+ }
+
+ public boolean isTakeOfferAccepted()
+ {
+ return takeOfferAccepted;
+ }
+
+ public void setTakeOfferAccepted(boolean takeOfferAccepted)
+ {
+ this.takeOfferAccepted = takeOfferAccepted;
+ }
+
+ public double getRequestedAmount()
+ {
+ return requestedAmount;
+ }
+
+ public void setRequestedAmount(double requestedAmount)
+ {
+ this.requestedAmount = requestedAmount;
+ }
+
+ public void setTakeOfferFeePayed(boolean takeOfferFeePayed)
+ {
+ this.takeOfferFeePayed = takeOfferFeePayed;
+ }
+
+ public void setTakeOfferFeePaymentConfirmed(boolean takeOfferFeePaymentConfirmed)
+ {
+ this.takeOfferFeePaymentConfirmed = takeOfferFeePaymentConfirmed;
+ }
+
+ public void setTakeOfferFeeTxID(String takeOfferFeeTxID)
+ {
+ this.takeOfferFeeTxID = takeOfferFeeTxID;
+ }
+}
diff --git a/src/main/java/io/bitsquare/trade/TradingFacade.java b/src/main/java/io/bitsquare/trade/TradingFacade.java
new file mode 100644
index 0000000000..03b5c3c39c
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/TradingFacade.java
@@ -0,0 +1,177 @@
+package io.bitsquare.trade;
+
+import com.google.inject.Inject;
+import io.bitsquare.btc.BlockChainFacade;
+import io.bitsquare.btc.KeyPair;
+import io.bitsquare.btc.MockWalletFacade;
+import io.bitsquare.crypto.ICryptoFacade;
+import io.bitsquare.msg.IMessageFacade;
+import io.bitsquare.msg.Message;
+import io.bitsquare.settings.Settings;
+import io.bitsquare.user.User;
+import io.bitsquare.util.Utils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.UUID;
+
+/**
+ * Main facade for operating with trade domain between GUI and services (msg, btc)
+ */
+public class TradingFacade
+{
+ private static final Logger log = LoggerFactory.getLogger(TradingFacade.class);
+
+ private final HashMap offers = new HashMap<>();
+ private final HashMap trades = new HashMap<>();
+ private final HashMap contracts = new HashMap<>();
+ private User user;
+ private IMessageFacade messageFacade;
+ private BlockChainFacade blockChainFacade;
+ private MockWalletFacade walletFacade;
+ private ICryptoFacade cryptoFacade;
+ private Settings settings;
+
+ @Inject
+ public TradingFacade(User user,
+ Settings settings,
+ IMessageFacade messageFacade,
+ BlockChainFacade blockChainFacade,
+ MockWalletFacade walletFacade,
+ ICryptoFacade cryptoFacade)
+ {
+ this.user = user;
+ this.settings = settings;
+ this.messageFacade = messageFacade;
+ this.blockChainFacade = blockChainFacade;
+ this.walletFacade = walletFacade;
+ this.cryptoFacade = cryptoFacade;
+ }
+
+ /**
+ * @param offer
+ */
+ public void placeNewOffer(Offer offer)
+ {
+ log.info("place New Offer");
+ offers.put(offer.getUid().toString(), offer);
+ messageFacade.broadcast(new Message(Message.BROADCAST_NEW_OFFER, offer));
+ }
+
+ /**
+ * Taker requests offerer to take the offer
+ *
+ * @param trade
+ */
+ public void sendTakeOfferRequest(Trade trade)
+ {
+ log.info("Taker asks offerer to take his offer");
+ messageFacade.send(new Message(Message.REQUEST_TAKE_OFFER, trade), trade.getOffer().getOfferer().getMessageID());
+ }
+
+
+ /**
+ * @param trade
+ * @return
+ */
+ public Contract createNewContract(Trade trade)
+ {
+ log.info("create new contract");
+ KeyPair address = walletFacade.createNewAddress();
+
+ Contract contract = new Contract(trade, address.getPubKey());
+ contract.setOfferer(trade.getOffer().getOfferer());
+ contract.setTaker(user);
+ contracts.put(trade.getUid().toString(), contract);
+ return contract;
+ }
+
+ /**
+ * @param contract
+ */
+ public void signContract(Contract contract)
+ {
+ log.info("sign Contract");
+
+ String contractAsJson = Utils.convertToJson(contract);
+
+ contract.getTrade().setJsonRepresentation(contractAsJson);
+ contract.getTrade().setSignature(cryptoFacade.sign(contractAsJson));
+ }
+
+ /**
+ * @param offer
+ * @return
+ */
+ public Trade createNewTrade(Offer offer)
+ {
+ log.info("create New Trade");
+ Trade trade = new Trade(offer);
+ trades.put(trade.getUid().toString(), trade);
+ return trade;
+ }
+
+
+ public HashMap getTrades()
+ {
+ return trades;
+ }
+
+ /**
+ * @param trade
+ */
+ public void payOfferFee(Trade trade)
+ {
+ log.info("Pay offer fee");
+
+ trade.setTakeOfferFeePayed(true);
+
+ String txID = UUID.randomUUID().toString();
+ trade.setTakeOfferFeePayed(true);
+ trade.setTakeOfferFeeTxID(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());
+ }
+
+
+ public void requestOffererDetailData()
+ {
+ log.info("Request offerer detail data");
+
+ }
+
+ /**
+ *
+ * @param trade
+ */
+ public void payToDepositTx(Trade trade)
+ {
+ log.info("create MultiSig address");
+
+ log.info("Create deposit tx");
+
+ log.info("Sign deposit tx");
+
+ log.info("Send deposit Tx");
+ messageFacade.send(new Message(Message.REQUEST_OFFER_FEE_PAYMENT_CONFIRM, trade), trade.getOffer().getOfferer().getMessageID());
+ }
+
+
+ /**
+ *
+ * @param trade
+ */
+ public void releaseBTC(Trade trade)
+ {
+ log.info("Sign payment tx");
+
+ log.info("Broadcast payment tx");
+
+ 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());
+ }
+
+
+}
diff --git a/src/main/java/io/bitsquare/trade/orderbook/IOrderBook.java b/src/main/java/io/bitsquare/trade/orderbook/IOrderBook.java
new file mode 100644
index 0000000000..9f59dfb0bb
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/orderbook/IOrderBook.java
@@ -0,0 +1,9 @@
+package io.bitsquare.trade.orderbook;
+
+import io.bitsquare.gui.trade.orderbook.OrderBookListItem;
+import javafx.collections.ObservableList;
+
+public interface IOrderBook
+{
+ ObservableList getFilteredList(OrderBookFilter orderBookFilter);
+}
diff --git a/src/main/java/io/bitsquare/trade/orderbook/MockOrderBook.java b/src/main/java/io/bitsquare/trade/orderbook/MockOrderBook.java
new file mode 100644
index 0000000000..cf7144f092
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/orderbook/MockOrderBook.java
@@ -0,0 +1,205 @@
+package io.bitsquare.trade.orderbook;
+
+import com.google.inject.Inject;
+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.trade.OfferConstraints;
+import io.bitsquare.user.BankDetails;
+import io.bitsquare.user.User;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.collections.transformation.FilteredList;
+
+import java.util.*;
+import java.util.function.Predicate;
+
+public class MockOrderBook implements IOrderBook
+{
+ private ObservableList orderBookListItems;
+ private Settings settings;
+
+ @Inject
+ public MockOrderBook(Settings settings)
+ {
+ this.settings = settings;
+ orderBookListItems = FXCollections.observableArrayList();
+ for (int i = 0; i < 100; i++)
+ {
+ orderBookListItems.add(getOfferListVO());
+ }
+ }
+
+ @Override
+ public ObservableList getFilteredList(OrderBookFilter orderBookFilter)
+ {
+ FilteredList filtered = orderBookListItems.filtered(new Predicate()
+ {
+ @Override
+ public boolean test(OrderBookListItem offerListVO)
+ {
+ boolean priceResult;
+ boolean amountResult = offerListVO.getOffer().getAmount() >= orderBookFilter.getAmount();
+ // 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.BUY && orderBookFilter.getPrice() > 0)
+ priceResult = offerListVO.getOffer().getPrice() <= orderBookFilter.getPrice();
+ else
+ priceResult = offerListVO.getOffer().getPrice() >= orderBookFilter.getPrice();
+ return priceResult && amountResult && directionResult && currencyResult;
+ }
+ });
+
+ //TODO use FilteredList
+ ObservableList result = FXCollections.observableArrayList();
+ result.addAll(filtered);
+ return result;
+ }
+
+ private OrderBookListItem getOfferListVO()
+ {
+ Offer i = getOffer();
+ return new OrderBookListItem(i);
+ }
+
+ public ArrayList getCurrencies()
+ {
+ ArrayList 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 otherCurrenciesSet = Currency.getAvailableCurrencies();
+ ArrayList otherCurrenciesList = new ArrayList<>();
+ otherCurrenciesList.addAll(otherCurrenciesSet);
+ Collections.sort(otherCurrenciesList, new CurrencyComparator());
+
+ currencies.addAll(otherCurrenciesList); */
+
+ return currencies;
+ }
+
+ private Offer getOffer()
+ {
+ double amount = Math.random() * 10 + 0.1;
+ amount = Converter.convertToDouble(Formatter.formatAmount(amount));
+ double minAmount = Math.random() * amount;
+ minAmount = Converter.convertToDouble(Formatter.formatAmount(minAmount));
+
+ String country = getCountries().get(0);
+ BankDetails bankDetails = new BankDetails();
+ String bankTransferType = getBankTransferTypes().get(0);
+ bankDetails.setBankTransferType(bankTransferType);
+ User offerer = new User(UUID.randomUUID().toString(), UUID.randomUUID().toString(), country, bankDetails);
+
+ Direction direction = Direction.BUY;
+ double price = 500 + Math.random() * 50;
+ if (Math.random() > 0.5)
+ {
+ direction = Direction.SELL;
+ price = 500 - Math.random() * 50;
+ }
+ Currency currency = (randomizeCurrencies(getCurrencies(), false)).get(0);
+ return new Offer(UUID.randomUUID(),
+ direction,
+ price,
+ amount,
+ minAmount,
+ currency,
+ offerer,
+ getRandomOfferConstraints()
+ );
+ }
+
+ public OfferConstraints getRandomOfferConstraints()
+ {
+ OfferConstraints offerConstraints = new OfferConstraints(getCountries(),
+ getLanguages(),
+ Double.valueOf(getCollaterals().get(0)),
+ getBankTransferTypes(),
+ getArbitrators().get(0),
+ randomizeStrings(settings.getAllIdentityVerifications(), false).get(0));
+
+ return offerConstraints;
+ }
+
+
+ private List getCountries()
+ {
+
+ return randomizeStrings(settings.getAllCountries(), false);
+ }
+
+ private List getLanguages()
+ {
+ return randomizeStrings(settings.getAllLanguages(), false);
+ }
+
+ private List getBankTransferTypes()
+ {
+ return randomizeStrings(settings.getAllBankTransferTypes(), false);
+ }
+
+ private List getArbitrators()
+ {
+ return randomizeStrings(settings.getAllArbitrators(), false);
+ }
+
+ private List getCollaterals()
+ {
+ return randomizeStrings(settings.getAllCollaterals(), false);
+ }
+
+
+ private List randomizeStrings(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 randomizeDouble(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 randomizeCurrencies(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;
+ }
+}
+
+class CurrencyComparator implements Comparator
+{
+ @Override
+ public int compare(Currency a, Currency b)
+ {
+ return a.getCurrencyCode().compareTo(b.getCurrencyCode());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/trade/orderbook/OrderBookFilter.java b/src/main/java/io/bitsquare/trade/orderbook/OrderBookFilter.java
new file mode 100644
index 0000000000..c9851f2501
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/orderbook/OrderBookFilter.java
@@ -0,0 +1,74 @@
+package io.bitsquare.trade.orderbook;
+
+import io.bitsquare.trade.Direction;
+import io.bitsquare.trade.OfferConstraints;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.beans.property.StringProperty;
+
+import java.util.Currency;
+
+public class OrderBookFilter
+{
+ private double price;
+ private double amount;
+ private Direction direction;
+ private Currency currency;
+ private final StringProperty currencyProperty = new SimpleStringProperty();
+ private OfferConstraints offerConstraints;
+
+ public void setAmount(double amount)
+ {
+ this.amount = amount;
+ }
+
+ public double getAmount()
+ {
+ return amount;
+ }
+
+ public void setDirection(Direction direction)
+ {
+ this.direction = direction;
+ }
+
+ public Direction getDirection()
+ {
+ return direction;
+ }
+
+ public double getPrice()
+ {
+ return price;
+ }
+
+ public void setPrice(double price)
+ {
+ this.price = price;
+ }
+
+ public Currency getCurrency()
+ {
+ return currency;
+ }
+
+ public StringProperty getCurrencyProperty()
+ {
+ return currencyProperty;
+ }
+
+ public void setCurrency(Currency currency)
+ {
+ this.currency = currency;
+ currencyProperty.set(currency.getCurrencyCode());
+ }
+
+ public OfferConstraints getOfferConstraints()
+ {
+ return offerConstraints;
+ }
+
+ public void setOfferConstraints(OfferConstraints offerConstraints)
+ {
+ this.offerConstraints = offerConstraints;
+ }
+}
diff --git a/src/main/java/io/bitsquare/trade/payment/process/BuyOffererPaymentProcess.java b/src/main/java/io/bitsquare/trade/payment/process/BuyOffererPaymentProcess.java
new file mode 100644
index 0000000000..f6efeaf5fb
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/payment/process/BuyOffererPaymentProcess.java
@@ -0,0 +1,40 @@
+package io.bitsquare.trade.payment.process;
+
+public class BuyOffererPaymentProcess extends PaymentProcess
+{
+ public BuyOffererPaymentProcess()
+ {
+ super();
+ }
+
+
+ // case 1 offerer step 1
+ private void buyOfferOfferer_payToDeposit()
+ {
+ onDataDepositTx();
+ payCollateral();
+ signDepositTx();
+ publishDepositTx();
+ sendMessageDepositTxPublished();
+ onBlockChainConfirmation();
+ }
+
+ // case 1 offerer step 2
+ private void buyOfferOfferer_payToDeposist()
+ {
+ payFiat();
+ sendMessageFiatTxInited();
+ createPayoutTx();
+ signPayoutTx();
+ sendDataPayoutTx();
+ onBlockChainConfirmation();
+ }
+
+ // case 1 offerer step 3
+ private void buyOfferOfferer_waitForRelease()
+ {
+ onMessagePayoutTxPublished();
+ onBlockChainConfirmation();
+ done();
+ }
+}
diff --git a/src/main/java/io/bitsquare/trade/payment/process/BuyTakerPaymentProcess.java b/src/main/java/io/bitsquare/trade/payment/process/BuyTakerPaymentProcess.java
new file mode 100644
index 0000000000..cc4856dbe1
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/payment/process/BuyTakerPaymentProcess.java
@@ -0,0 +1,39 @@
+package io.bitsquare.trade.payment.process;
+
+public class BuyTakerPaymentProcess extends PaymentProcess
+{
+
+ public BuyTakerPaymentProcess()
+ {
+ super();
+ }
+
+ @Override
+ public void executeStep0()
+ {
+ // bitcoinServices.createMultiSig();
+ createDepositTx();
+ payPaymentAndCollateral();
+ signDepositTx();
+ sendDataDepositTx();
+ }
+
+ @Override
+ public void executeStep1()
+ {
+ onMessageDepositTxPublished();
+ onMessageFiatTxInited();
+ onUserInputFiatReceived();
+ onDataPayoutTx();
+ }
+
+ @Override
+ public void executeStep2()
+ {
+ signPayoutTx();
+ publishPayoutTx();
+ sendMessagePayoutTxPublished();
+ onBlockChainConfirmation();
+ done();
+ }
+}
diff --git a/src/main/java/io/bitsquare/trade/payment/process/PaymentProcess.java b/src/main/java/io/bitsquare/trade/payment/process/PaymentProcess.java
new file mode 100644
index 0000000000..accf29fc3b
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/payment/process/PaymentProcess.java
@@ -0,0 +1,244 @@
+package io.bitsquare.trade.payment.process;
+
+import com.google.inject.Inject;
+import io.bitsquare.btc.BlockChainFacade;
+import io.bitsquare.btc.MockWalletFacade;
+import io.bitsquare.msg.IMessageFacade;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PaymentProcess
+{
+ private static final Logger log = LoggerFactory.getLogger(PaymentProcess.class);
+ private IMessageFacade messageService;
+ private BlockChainFacade bitcoinServices;
+
+ protected String offererDepositPubKey;
+ protected String offererPayoutAddress;
+ protected String offererChangeAddress;
+ protected String offererTotalInputPayment;
+ protected String offererOutputPayment;
+
+ protected String takerDepositPubKey;
+ protected String takerPayoutAddress;
+ protected String takerChangeAddress;
+ protected String takerTotalInputPayment;
+ protected String takerOutputPayment;
+
+ protected String multiSigAddress;
+ private MockWalletFacade wallet;
+
+ public PaymentProcess()
+ {
+ }
+
+ @Inject
+ public void setMessageService(IMessageFacade messageService)
+ {
+ this.messageService = messageService;
+ }
+
+ @Inject
+ public void setWallet(MockWalletFacade wallet)
+ {
+ this.wallet = wallet;
+ }
+
+ @Inject
+ public void setBtcServices(BlockChainFacade bitcoinServices)
+ {
+ this.bitcoinServices = bitcoinServices;
+ }
+
+
+ public void executeStep0()
+ {
+ }
+
+ public void executeStep1()
+ {
+ }
+
+ public void executeStep2()
+ {
+ }
+
+ public void executeStep3()
+ {
+ }
+
+
+ protected void createDepositTx()
+ {
+ //wallet.getInputs(offererTotalInputPayment);
+ //bitcoinServices.createTx(taker);
+ }
+
+ protected void payPaymentAndCollateral()
+ {
+ }
+
+ protected void signDepositTx()
+ {
+ }
+
+ protected void sendDataDepositTx()
+ {
+ }
+
+ protected void onMessageFiatTxInited()
+ {
+ }
+
+ protected void onUserInputFiatReceived()
+ {
+ }
+
+ protected void onDataPayoutTx()
+ {
+ }
+
+ protected void onMessageDepositTxPublished()
+ {
+ }
+
+ protected void signPayoutTx()
+ {
+ }
+
+ protected void publishPayoutTx()
+ {
+ }
+
+ protected void sendMessagePayoutTxPublished()
+ {
+ }
+
+ protected void onBlockChainConfirmation()
+ {
+ }
+
+ protected void done()
+ {
+ }
+
+ protected void onDataDepositTx()
+ {
+ }
+
+ protected void payCollateral()
+ {
+ }
+
+ protected void publishDepositTx()
+ {
+ }
+
+ protected void sendMessageDepositTxPublished()
+ {
+ }
+
+ protected void payFiat()
+ {
+ }
+
+ protected void sendMessageFiatTxInited()
+ {
+ }
+
+ protected void createPayoutTx()
+ {
+ }
+
+ protected void sendDataPayoutTx()
+ {
+ }
+
+ protected void onMessagePayoutTxPublished()
+ {
+ }
+
+ /*
+ case 1:
+ BUY offer
+ taker:
+ 1 PAY BTC
+ create ms
+ create deposit tx
+ pay payment+coll
+ signContract
+ send deposit tx to offerer
+ 2 WAIT FOR FIAT
+ wait for pub tx info msg
+ wait for build fiat info msg
+ wait for fiat on bank
+ wait for payout tx
+ 3 RELEASE BTC
+ signContract payout tx
+ pub payout tx
+ send info to offerer
+ wait for >= 1 confirm
+ DONE
+ offerer:
+ 1 WAIT FOR BTC PAYMENT
+ wait for deposit tx
+ pay coll
+ signContract
+ pub deposit tx
+ send info msg to taker
+ wait for >=1 confirm
+ 2 PAY FIAT
+ build fiat
+ send info msg to taker
+ create payout tx
+ signContract payout tx
+ send payout tx to taker
+ 3 WAIT FOR BTC RELEASE
+ wait for release info msg
+ wait for >= 1 confirm
+ DONE
+
+ case 2:
+ SELL offer
+ taker:
+ 1 PAY COLL
+ create ms
+ create deposit tx
+ pay coll
+ signContract
+ send deposit tx to offerer
+ 2 WAIT FOR BTC PAYMENT
+ wait for pub tx info msg
+ wait for >=1 confirm
+ 3 PAY FIAT -> Same
+ build fiat
+ send info msg to taker
+ create payout tx
+ signContract payout tx
+ send payout tx to offerer
+ 4 WAIT FOR BTC RELEASE -> Same
+ wait for release info msg
+ wait for >= 1 confirm
+ DONE
+ offerer:
+ 1 WAIT FOR COLL
+ wait for deposit tx
+ 2 PAY BTC
+ pay coll+payment
+ signContract
+ pub deposit tx
+ send info msg to taker
+ 3 WAIT FOR FIAT
+ wait for build fiat info msg
+ wait for payout tx
+ wait for fiat on bank
+ 4 RELEASE BTC
+ signContract payout tx
+ pub payout tx
+ send info to taker
+ wait for >= 1 confirm
+ DONE
+
+
+ */
+}
diff --git a/src/main/java/io/bitsquare/trade/payment/process/SellOffererPaymentProcess.java b/src/main/java/io/bitsquare/trade/payment/process/SellOffererPaymentProcess.java
new file mode 100644
index 0000000000..20eb61ad17
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/payment/process/SellOffererPaymentProcess.java
@@ -0,0 +1,44 @@
+package io.bitsquare.trade.payment.process;
+
+public class SellOffererPaymentProcess extends PaymentProcess
+{
+ public SellOffererPaymentProcess()
+ {
+ super();
+ }
+
+
+ // case 2 offerer step 1
+ private void sellOfferOfferer_waitForCollateralPayedByPeer()
+ {
+ onDataDepositTx();
+ }
+
+ // case 2 offerer step 2
+ private void sellOfferOfferer_payToDeposit()
+ {
+ payPaymentAndCollateral();
+ signDepositTx();
+ publishDepositTx();
+ sendMessageDepositTxPublished();
+ }
+
+ // case 2 offerer step 3
+ private void sellOfferOfferer_waitForFiat()
+ {
+ onMessageFiatTxInited();
+ onDataPayoutTx();
+ onUserInputFiatReceived();
+ }
+
+ // case 2 offerer step 4
+ private void sellOfferOfferer_releasePayment()
+ {
+ signPayoutTx();
+ publishPayoutTx();
+ sendMessagePayoutTxPublished();
+ onBlockChainConfirmation();
+ done();
+ }
+
+}
diff --git a/src/main/java/io/bitsquare/trade/payment/process/SellTakerPaymentProcess.java b/src/main/java/io/bitsquare/trade/payment/process/SellTakerPaymentProcess.java
new file mode 100644
index 0000000000..b3a9fd3864
--- /dev/null
+++ b/src/main/java/io/bitsquare/trade/payment/process/SellTakerPaymentProcess.java
@@ -0,0 +1,45 @@
+package io.bitsquare.trade.payment.process;
+
+public class SellTakerPaymentProcess extends PaymentProcess
+{
+ public SellTakerPaymentProcess()
+ {
+ super();
+ }
+
+
+ // case 2 taker step 1
+ private void sellOfferTaker_payToDeposit()
+ {
+ //createMultiSig();
+ createDepositTx();
+ payCollateral();
+ signDepositTx();
+ sendDataDepositTx();
+ }
+
+ // case 2 taker step 2
+ private void sellOfferTaker_waitForDepositPublished()
+ {
+ onMessageDepositTxPublished();
+ onBlockChainConfirmation();
+ }
+
+ // case 2 taker step 3
+ private void sellOfferTaker_payFiat()
+ {
+ payFiat();
+ sendMessageFiatTxInited();
+ createPayoutTx();
+ signPayoutTx();
+ sendDataPayoutTx();
+ }
+
+ // case 2 taker step 4
+ private void sellOfferTaker_waitForRelease()
+ {
+ onMessagePayoutTxPublished();
+ onBlockChainConfirmation();
+ done();
+ }
+}
diff --git a/src/main/java/io/bitsquare/user/BankDetails.java b/src/main/java/io/bitsquare/user/BankDetails.java
new file mode 100644
index 0000000000..f18cc68424
--- /dev/null
+++ b/src/main/java/io/bitsquare/user/BankDetails.java
@@ -0,0 +1,61 @@
+package io.bitsquare.user;
+
+public class BankDetails
+{
+ private String bankTransferType;
+ private String accountPrimaryID;
+ private String accountSecondaryID;
+ private String accountHolderName;
+
+ public BankDetails(String bankTransferType, String accountPrimaryID, String accountSecondaryID, String accountHolderName)
+ {
+ this.bankTransferType = bankTransferType;
+ this.accountPrimaryID = accountPrimaryID;
+ this.accountSecondaryID = accountSecondaryID;
+ this.accountHolderName = accountHolderName;
+ }
+
+ public BankDetails()
+ {
+ }
+
+ public void setBankTransferType(String bankTransferType)
+ {
+ this.bankTransferType = bankTransferType;
+ }
+
+ public String getAccountPrimaryID()
+ {
+ return accountPrimaryID;
+ }
+
+ public void setAccountPrimaryID(String accountPrimaryID)
+ {
+ this.accountPrimaryID = accountPrimaryID;
+ }
+
+ public String getAccountSecondaryID()
+ {
+ return accountSecondaryID;
+ }
+
+ public void setAccountSecondaryID(String accountSecondaryID)
+ {
+ this.accountSecondaryID = accountSecondaryID;
+ }
+
+ public String getAccountHolderName()
+ {
+ return accountHolderName;
+ }
+
+ public void setAccountHolderName(String accountHolderName)
+ {
+ this.accountHolderName = accountHolderName;
+ }
+
+ public String getBankTransferType()
+ {
+ return bankTransferType;
+ }
+}
diff --git a/src/main/java/io/bitsquare/user/User.java b/src/main/java/io/bitsquare/user/User.java
new file mode 100644
index 0000000000..ebb9889690
--- /dev/null
+++ b/src/main/java/io/bitsquare/user/User.java
@@ -0,0 +1,74 @@
+package io.bitsquare.user;
+
+public class User
+{
+ private String accountID;
+ private String messageID;
+ private boolean isOnline;
+ private BankDetails bankDetails;
+ private String country;
+
+ public User(String accountID, String messageID, String country, BankDetails bankDetails)
+ {
+ this.accountID = accountID;
+ this.messageID = messageID;
+ this.country = country;
+ this.bankDetails = bankDetails;
+ }
+
+ public User()
+ {
+ }
+
+ public String getMessageID()
+ {
+ return messageID;
+ }
+
+ public void setMessageID(String messageID)
+ {
+ this.messageID = messageID;
+ }
+
+ public String getAccountID()
+ {
+ return accountID;
+ }
+
+ public void setAccountID(String accountID)
+ {
+ this.accountID = accountID;
+ }
+
+ public void setCountry(String country)
+ {
+ this.country = country;
+ }
+
+ public String getCountry()
+ {
+ return country;
+ }
+
+
+ public BankDetails getBankDetails()
+ {
+ return bankDetails;
+ }
+
+ public void setBankDetails(BankDetails bankDetails)
+ {
+ this.bankDetails = bankDetails;
+ }
+
+
+ public boolean getOnline()
+ {
+ return isOnline;
+ }
+
+ public void setOnline(boolean online)
+ {
+ this.isOnline = online;
+ }
+}
diff --git a/src/main/java/io/bitsquare/util/Utils.java b/src/main/java/io/bitsquare/util/Utils.java
new file mode 100644
index 0000000000..13d5cd41d5
--- /dev/null
+++ b/src/main/java/io/bitsquare/util/Utils.java
@@ -0,0 +1,43 @@
+package io.bitsquare.util;
+
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import java.io.*;
+
+public class Utils
+{
+ public static String convertToJson(Object object)
+ {
+ Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
+ return gson.toJson(object);
+ }
+
+ public static Object copy(Object orig)
+ {
+ Object obj = null;
+ try
+ {
+ // Write the object out to a byte array
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream out = new ObjectOutputStream(bos);
+ out.writeObject(orig);
+ out.flush();
+ out.close();
+
+ // Make an input stream from the byte array and read
+ // a copy of the object back in.
+ ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
+ obj = in.readObject();
+ } catch (IOException e)
+ {
+ e.printStackTrace();
+ } catch (ClassNotFoundException cnfe)
+ {
+ cnfe.printStackTrace();
+ }
+ return obj;
+ }
+
+}
diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..ff5711f4f5
--- /dev/null
+++ b/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+Archiver-Version: Plexus Archiver
+Created-By: Apache Maven
+Built-By: Manfred Karrer
+Build-Jdk: 1.8.0
+Main-Class: io.bitsquare.BitSquare
diff --git a/src/main/resources/bitsquare.properties b/src/main/resources/bitsquare.properties
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/main/resources/i18n/displayStrings_de_DE.properties b/src/main/resources/i18n/displayStrings_de_DE.properties
new file mode 100644
index 0000000000..89b8f2dc80
--- /dev/null
+++ b/src/main/resources/i18n/displayStrings_de_DE.properties
@@ -0,0 +1 @@
+currency=Währung
\ No newline at end of file
diff --git a/src/main/resources/i18n/displayStrings_en_US.properties b/src/main/resources/i18n/displayStrings_en_US.properties
new file mode 100644
index 0000000000..cf3b41cbbd
--- /dev/null
+++ b/src/main/resources/i18n/displayStrings_en_US.properties
@@ -0,0 +1 @@
+currency=Currency
\ No newline at end of file
diff --git a/src/main/resources/images/add.png b/src/main/resources/images/add.png
new file mode 100644
index 0000000000..f1495b0376
Binary files /dev/null and b/src/main/resources/images/add.png differ
diff --git a/src/main/resources/images/buy.png b/src/main/resources/images/buy.png
new file mode 100644
index 0000000000..6b0d76836c
Binary files /dev/null and b/src/main/resources/images/buy.png differ
diff --git a/src/main/resources/images/buy_white.png b/src/main/resources/images/buy_white.png
new file mode 100644
index 0000000000..cdbab3ed91
Binary files /dev/null and b/src/main/resources/images/buy_white.png differ
diff --git a/src/main/resources/images/edit.png b/src/main/resources/images/edit.png
new file mode 100644
index 0000000000..bda0d24c90
Binary files /dev/null and b/src/main/resources/images/edit.png differ
diff --git a/src/main/resources/images/edit_pen.png b/src/main/resources/images/edit_pen.png
new file mode 100644
index 0000000000..170587da45
Binary files /dev/null and b/src/main/resources/images/edit_pen.png differ
diff --git a/src/main/resources/images/funds.png b/src/main/resources/images/funds.png
new file mode 100644
index 0000000000..259bf05f40
Binary files /dev/null and b/src/main/resources/images/funds.png differ
diff --git a/src/main/resources/images/history.png b/src/main/resources/images/history.png
new file mode 100644
index 0000000000..226ced4395
Binary files /dev/null and b/src/main/resources/images/history.png differ
diff --git a/src/main/resources/images/home.png b/src/main/resources/images/home.png
new file mode 100644
index 0000000000..f2196f953e
Binary files /dev/null and b/src/main/resources/images/home.png differ
diff --git a/src/main/resources/images/info.png b/src/main/resources/images/info.png
new file mode 100644
index 0000000000..0b5bbe58af
Binary files /dev/null and b/src/main/resources/images/info.png differ
diff --git a/src/main/resources/images/list.png b/src/main/resources/images/list.png
new file mode 100644
index 0000000000..3a335a121c
Binary files /dev/null and b/src/main/resources/images/list.png differ
diff --git a/src/main/resources/images/msg.png b/src/main/resources/images/msg.png
new file mode 100644
index 0000000000..f286405d95
Binary files /dev/null and b/src/main/resources/images/msg.png differ
diff --git a/src/main/resources/images/nav_buy.png b/src/main/resources/images/nav_buy.png
new file mode 100644
index 0000000000..31b2f868f2
Binary files /dev/null and b/src/main/resources/images/nav_buy.png differ
diff --git a/src/main/resources/images/nav_buy_active.png b/src/main/resources/images/nav_buy_active.png
new file mode 100644
index 0000000000..3e3bc05ee4
Binary files /dev/null and b/src/main/resources/images/nav_buy_active.png differ
diff --git a/src/main/resources/images/nav_sell.png b/src/main/resources/images/nav_sell.png
new file mode 100644
index 0000000000..90f593a884
Binary files /dev/null and b/src/main/resources/images/nav_sell.png differ
diff --git a/src/main/resources/images/nav_sell_active.png b/src/main/resources/images/nav_sell_active.png
new file mode 100644
index 0000000000..3f4b0e8ad1
Binary files /dev/null and b/src/main/resources/images/nav_sell_active.png differ
diff --git a/src/main/resources/images/orders.png b/src/main/resources/images/orders.png
new file mode 100644
index 0000000000..62365d6ee4
Binary files /dev/null and b/src/main/resources/images/orders.png differ
diff --git a/src/main/resources/images/payment_step1.png b/src/main/resources/images/payment_step1.png
new file mode 100644
index 0000000000..16dc4cbecf
Binary files /dev/null and b/src/main/resources/images/payment_step1.png differ
diff --git a/src/main/resources/images/payment_step2.png b/src/main/resources/images/payment_step2.png
new file mode 100644
index 0000000000..bb327b9bc6
Binary files /dev/null and b/src/main/resources/images/payment_step2.png differ
diff --git a/src/main/resources/images/payment_step3.png b/src/main/resources/images/payment_step3.png
new file mode 100644
index 0000000000..9c1b3899f8
Binary files /dev/null and b/src/main/resources/images/payment_step3.png differ
diff --git a/src/main/resources/images/payment_step4.png b/src/main/resources/images/payment_step4.png
new file mode 100644
index 0000000000..f70ee6e7c2
Binary files /dev/null and b/src/main/resources/images/payment_step4.png differ
diff --git a/src/main/resources/images/payment_step5.png b/src/main/resources/images/payment_step5.png
new file mode 100644
index 0000000000..f6e4d12b2f
Binary files /dev/null and b/src/main/resources/images/payment_step5.png differ
diff --git a/src/main/resources/images/peers.png b/src/main/resources/images/peers.png
new file mode 100644
index 0000000000..8ac8c3d341
Binary files /dev/null and b/src/main/resources/images/peers.png differ
diff --git a/src/main/resources/images/remove.png b/src/main/resources/images/remove.png
new file mode 100644
index 0000000000..8cdb068771
Binary files /dev/null and b/src/main/resources/images/remove.png differ
diff --git a/src/main/resources/images/remove_minus.png b/src/main/resources/images/remove_minus.png
new file mode 100644
index 0000000000..e12e49a477
Binary files /dev/null and b/src/main/resources/images/remove_minus.png differ
diff --git a/src/main/resources/images/remove_minus_8.png b/src/main/resources/images/remove_minus_8.png
new file mode 100644
index 0000000000..0ff14b1903
Binary files /dev/null and b/src/main/resources/images/remove_minus_8.png differ
diff --git a/src/main/resources/images/remove_minus_9.png b/src/main/resources/images/remove_minus_9.png
new file mode 100644
index 0000000000..28f6a983b4
Binary files /dev/null and b/src/main/resources/images/remove_minus_9.png differ
diff --git a/src/main/resources/images/sell.png b/src/main/resources/images/sell.png
new file mode 100644
index 0000000000..10924574bb
Binary files /dev/null and b/src/main/resources/images/sell.png differ
diff --git a/src/main/resources/images/sell_white.png b/src/main/resources/images/sell_white.png
new file mode 100644
index 0000000000..355aa77f28
Binary files /dev/null and b/src/main/resources/images/sell_white.png differ
diff --git a/src/main/resources/images/settings.png b/src/main/resources/images/settings.png
new file mode 100644
index 0000000000..84038d1b97
Binary files /dev/null and b/src/main/resources/images/settings.png differ
diff --git a/src/main/resources/images/step1.png b/src/main/resources/images/step1.png
new file mode 100644
index 0000000000..3dbc3b1fdf
Binary files /dev/null and b/src/main/resources/images/step1.png differ
diff --git a/src/main/resources/images/step2.png b/src/main/resources/images/step2.png
new file mode 100644
index 0000000000..8ed761a0f2
Binary files /dev/null and b/src/main/resources/images/step2.png differ
diff --git a/src/main/resources/images/step3.png b/src/main/resources/images/step3.png
new file mode 100644
index 0000000000..dafd5d6e1a
Binary files /dev/null and b/src/main/resources/images/step3.png differ
diff --git a/src/main/resources/images/step4.png b/src/main/resources/images/step4.png
new file mode 100644
index 0000000000..10a7e51e44
Binary files /dev/null and b/src/main/resources/images/step4.png differ
diff --git a/src/main/resources/images/step5.png b/src/main/resources/images/step5.png
new file mode 100644
index 0000000000..4fcbdb39ce
Binary files /dev/null and b/src/main/resources/images/step5.png differ
diff --git a/src/main/resources/images/trade.png b/src/main/resources/images/trade.png
new file mode 100644
index 0000000000..15471f0e52
Binary files /dev/null and b/src/main/resources/images/trade.png differ
diff --git a/src/main/resources/images/trash.png b/src/main/resources/images/trash.png
new file mode 100644
index 0000000000..2ef8994fd2
Binary files /dev/null and b/src/main/resources/images/trash.png differ
diff --git a/src/main/resources/images/unused/add.png b/src/main/resources/images/unused/add.png
new file mode 100644
index 0000000000..b1134d6dac
Binary files /dev/null and b/src/main/resources/images/unused/add.png differ
diff --git a/src/main/resources/images/unused/add_10.png b/src/main/resources/images/unused/add_10.png
new file mode 100644
index 0000000000..5945f67957
Binary files /dev/null and b/src/main/resources/images/unused/add_10.png differ
diff --git a/src/main/resources/images/unused/add_12.png b/src/main/resources/images/unused/add_12.png
new file mode 100644
index 0000000000..9399b1ae6b
Binary files /dev/null and b/src/main/resources/images/unused/add_12.png differ
diff --git a/src/main/resources/images/unused/add_16.png b/src/main/resources/images/unused/add_16.png
new file mode 100644
index 0000000000..ee10975d5d
Binary files /dev/null and b/src/main/resources/images/unused/add_16.png differ
diff --git a/src/main/resources/images/unused/add_8.png b/src/main/resources/images/unused/add_8.png
new file mode 100644
index 0000000000..e6eb6eb0f1
Binary files /dev/null and b/src/main/resources/images/unused/add_8.png differ
diff --git a/src/main/resources/images/unused/edit.png b/src/main/resources/images/unused/edit.png
new file mode 100644
index 0000000000..24eb3b4a91
Binary files /dev/null and b/src/main/resources/images/unused/edit.png differ
diff --git a/src/main/resources/images/unused/mail.png b/src/main/resources/images/unused/mail.png
new file mode 100644
index 0000000000..1b714f45b1
Binary files /dev/null and b/src/main/resources/images/unused/mail.png differ
diff --git a/src/main/resources/images/unused/offline.png b/src/main/resources/images/unused/offline.png
new file mode 100644
index 0000000000..7b63719d9d
Binary files /dev/null and b/src/main/resources/images/unused/offline.png differ
diff --git a/src/main/resources/images/unused/online.png b/src/main/resources/images/unused/online.png
new file mode 100644
index 0000000000..c51f1dc1af
Binary files /dev/null and b/src/main/resources/images/unused/online.png differ
diff --git a/src/main/resources/images/unused/remove.png b/src/main/resources/images/unused/remove.png
new file mode 100644
index 0000000000..c85434e0fd
Binary files /dev/null and b/src/main/resources/images/unused/remove.png differ
diff --git a/src/main/resources/images/unused/remove_12.png b/src/main/resources/images/unused/remove_12.png
new file mode 100644
index 0000000000..df303a78b8
Binary files /dev/null and b/src/main/resources/images/unused/remove_12.png differ
diff --git a/src/main/resources/images/unused/remove_6.png b/src/main/resources/images/unused/remove_6.png
new file mode 100644
index 0000000000..37b452a8c3
Binary files /dev/null and b/src/main/resources/images/unused/remove_6.png differ
diff --git a/src/main/resources/images/unused/remove_8.png b/src/main/resources/images/unused/remove_8.png
new file mode 100644
index 0000000000..9d2b403a1a
Binary files /dev/null and b/src/main/resources/images/unused/remove_8.png differ
diff --git a/src/main/resources/images/unused/remove_9.png b/src/main/resources/images/unused/remove_9.png
new file mode 100644
index 0000000000..d466aa4e67
Binary files /dev/null and b/src/main/resources/images/unused/remove_9.png differ