initial commit. gui prototype v 0.1
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/docs
|
||||
/log
|
||||
/target
|
||||
/bin
|
||||
.idea
|
||||
bitsquare.iml
|
202
COPYING
Normal file
@ -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.
|
37
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
|
||||
|
||||
|
BIN
design/navIcons.psd
Normal file
89
pom.xml
Normal file
@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>bitsquare</groupId>
|
||||
<artifactId>bitsquare</artifactId>
|
||||
<version>0.1</version>
|
||||
|
||||
<name>BitSquare</name>
|
||||
<description>A P2P Fiat-Bitcoin Exchange</description>
|
||||
<url>https://www.bitsquare.io</url>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache 2</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<scm>
|
||||
<url>https://github.com/bitsquare/bitsquare</url>
|
||||
</scm>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.0.9</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava-base</artifactId>
|
||||
<version>r03</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.2.4</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.controlsfx</groupId>
|
||||
<artifactId>controlsfx</artifactId>
|
||||
<version>8.0.5</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
</project>
|
51
src/main/java/io/bitsquare/BitSquare.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
17
src/main/java/io/bitsquare/btc/BlockChainFacade.java
Normal file
@ -0,0 +1,17 @@
|
||||
package io.bitsquare.btc;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* Gateway to blockchain
|
||||
*/
|
||||
public class BlockChainFacade
|
||||
{
|
||||
@Inject
|
||||
public BlockChainFacade()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
15
src/main/java/io/bitsquare/btc/BtcFormatter.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
11
src/main/java/io/bitsquare/btc/Fees.java
Normal file
@ -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");
|
||||
|
||||
}
|
12
src/main/java/io/bitsquare/btc/IWalletFacade.java
Normal file
@ -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();
|
||||
}
|
33
src/main/java/io/bitsquare/btc/KeyPair.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
52
src/main/java/io/bitsquare/btc/MockWalletFacade.java
Normal file
@ -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());
|
||||
}
|
||||
}
|
6
src/main/java/io/bitsquare/crypto/ICryptoFacade.java
Normal file
@ -0,0 +1,6 @@
|
||||
package io.bitsquare.crypto;
|
||||
|
||||
public interface ICryptoFacade
|
||||
{
|
||||
String sign(String data);
|
||||
}
|
16
src/main/java/io/bitsquare/crypto/MockCryptoFacade.java
Normal file
@ -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";
|
||||
}
|
||||
}
|
44
src/main/java/io/bitsquare/di/BitSquareModule.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
29
src/main/java/io/bitsquare/di/GuiceControllerFactory.java
Normal file
@ -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)}.
|
||||
* <p/>
|
||||
* Once set, make sure you do <b>not</b> use the static methods on
|
||||
* {@link javafx.fxml.FXMLLoader} when creating your JavaFX node.
|
||||
*/
|
||||
public class GuiceControllerFactory implements Callback<Class<?>, Object>
|
||||
{
|
||||
|
||||
private Injector injector;
|
||||
|
||||
public GuiceControllerFactory(Injector injector)
|
||||
{
|
||||
this.injector = injector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object call(Class<?> aClass)
|
||||
{
|
||||
return injector.getInstance(aClass);
|
||||
}
|
||||
}
|
28
src/main/java/io/bitsquare/di/GuiceFXMLLoader.java
Normal file
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
6
src/main/java/io/bitsquare/gui/IChildController.java
Normal file
@ -0,0 +1,6 @@
|
||||
package io.bitsquare.gui;
|
||||
|
||||
public interface IChildController
|
||||
{
|
||||
void setNavigationController(INavigationController navigationController);
|
||||
}
|
19
src/main/java/io/bitsquare/gui/INavigationController.java
Normal file
@ -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);
|
||||
}
|
165
src/main/java/io/bitsquare/gui/MainController.java
Normal file
@ -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<Currency>()
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue ov, Currency oldValue, Currency newValue)
|
||||
{
|
||||
orderBookFilter.setCurrency(newValue);
|
||||
settings.setCurrency(newValue);
|
||||
}
|
||||
});
|
||||
holder.getChildren().add(currencyComboBox);
|
||||
rightNavPane.getChildren().add(holder);
|
||||
}
|
||||
}
|
14
src/main/java/io/bitsquare/gui/MainView.fxml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.layout.*?>
|
||||
<AnchorPane id="root-pane" minHeight="300" minWidth="400" prefHeight="600" prefWidth="800"
|
||||
stylesheets="/io/bitsquare/gui/global.css" xmlns:fx="http://javafx.com/fxml/1"
|
||||
xmlns="http://javafx.com/javafx/8" fx:controller="io.bitsquare.gui.MainController">
|
||||
|
||||
<children>
|
||||
<HBox fx:id="leftNavPane" spacing="20" AnchorPane.leftAnchor="10" AnchorPane.topAnchor="5"/>
|
||||
<HBox fx:id="rightNavPane" spacing="10" AnchorPane.rightAnchor="10" AnchorPane.topAnchor="5"/>
|
||||
<AnchorPane id="content-pane" fx:id="contentPane" AnchorPane.bottomAnchor="0" AnchorPane.leftAnchor="0"
|
||||
AnchorPane.rightAnchor="0" AnchorPane.topAnchor="60"/>
|
||||
</children>
|
||||
</AnchorPane>
|
37
src/main/java/io/bitsquare/gui/components/BuySellSwitch.java
Normal file
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
23
src/main/java/io/bitsquare/gui/components/HSpacer.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
package io.bitsquare.gui.components;
|
||||
|
||||
import javafx.scene.control.ScrollPane;
|
||||
|
||||
public class NoFocusScrollPane extends ScrollPane
|
||||
{
|
||||
public void requestFocus()
|
||||
{
|
||||
// prevent focus
|
||||
}
|
||||
}
|
66
src/main/java/io/bitsquare/gui/components/PTableColumn.java
Normal file
@ -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<S, T> extends javafx.scene.control.TableColumn<S, T>
|
||||
{
|
||||
|
||||
private final DoubleProperty percentageWidth = new SimpleDoubleProperty(0);
|
||||
|
||||
public PTableColumn()
|
||||
{
|
||||
tableViewProperty().addListener(new ChangeListener<TableView<S>>()
|
||||
{
|
||||
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends TableView<S>> ov, TableView<S> t, TableView<S> 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));
|
||||
}
|
||||
}
|
23
src/main/java/io/bitsquare/gui/components/VSpacer.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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<T> extends Control
|
||||
{
|
||||
private List<ProcessStepItem> processStepItems;
|
||||
|
||||
public ProcessStepBar(List<ProcessStepItem> processStepItems)
|
||||
{
|
||||
this.processStepItems = processStepItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Skin<?> createDefaultSkin()
|
||||
{
|
||||
return new ProcessStepBarSkin<>(this);
|
||||
}
|
||||
|
||||
List<ProcessStepItem> getProcessStepItems()
|
||||
{
|
||||
return processStepItems;
|
||||
}
|
||||
|
||||
public void next()
|
||||
{
|
||||
((ProcessStepBarSkin) getSkin()).next();
|
||||
}
|
||||
}
|
@ -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<T> extends BehaviorSkinBase<ProcessStepBar<T>, BehaviorBase<ProcessStepBar<T>>>
|
||||
{
|
||||
LabelWithBorder currentLabelWithBorder;
|
||||
LabelWithBorder prevLabelWithBorder;
|
||||
final ProcessStepBar<T> controller;
|
||||
int index;
|
||||
List<LabelWithBorder> labelWithBorders;
|
||||
|
||||
public ProcessStepBarSkin(final ProcessStepBar<T> control)
|
||||
{
|
||||
super(control, new BehaviorBase<>(control, Collections.<KeyBinding>emptyList()));
|
||||
|
||||
controller = getSkinnable();
|
||||
|
||||
int i = 0;
|
||||
labelWithBorders = new ArrayList<>();
|
||||
int size = controller.getProcessStepItems().size();
|
||||
for (Iterator<ProcessStepItem> 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<ProcessStepItem> processStepItems = new ArrayList();
|
||||
protected ProcessStepBar<String> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
26
src/main/java/io/bitsquare/gui/funds/FundsController.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
|
6
src/main/java/io/bitsquare/gui/funds/FundsView.fxml
Normal file
@ -0,0 +1,6 @@
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<Pane fx:controller="io.bitsquare.gui.funds.FundsController"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
<Label text="Wallet"/>
|
||||
</Pane>
|
109
src/main/java/io/bitsquare/gui/global.css
Normal file
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
6
src/main/java/io/bitsquare/gui/history/HistoryView.fxml
Normal file
@ -0,0 +1,6 @@
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<Pane fx:controller="io.bitsquare.gui.history.HistoryController"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
<Label text="Histroy"/>
|
||||
</Pane>
|
32
src/main/java/io/bitsquare/gui/home/HomeController.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
4
src/main/java/io/bitsquare/gui/home/HomeView.fxml
Normal file
@ -0,0 +1,4 @@
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<VBox fx:id="rootContainer" fx:controller="io.bitsquare.gui.home.HomeController" spacing="10"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
</VBox>
|
50
src/main/java/io/bitsquare/gui/msg/MockDelay.java
Normal file
@ -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<String> 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<String>
|
||||
{
|
||||
private String expectedMsg;
|
||||
|
||||
Task(String expectedMsg)
|
||||
{
|
||||
this.expectedMsg = expectedMsg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String call() throws Exception
|
||||
{
|
||||
Thread.sleep(1000); // 1 seconds pause
|
||||
return expectedMsg;
|
||||
}
|
||||
}
|
27
src/main/java/io/bitsquare/gui/msg/MsgController.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
6
src/main/java/io/bitsquare/gui/msg/MsgView.fxml
Normal file
@ -0,0 +1,6 @@
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<Pane fx:controller="io.bitsquare.gui.msg.MsgController"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
<Label text="Msg"/>
|
||||
</Pane>
|
30
src/main/java/io/bitsquare/gui/orders/OrdersController.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
6
src/main/java/io/bitsquare/gui/orders/OrdersView.fxml
Normal file
@ -0,0 +1,6 @@
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<Pane fx:controller="io.bitsquare.gui.orders.OrdersController"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
<Label text="Orders"/>
|
||||
</Pane>
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<Pane fx:controller="io.bitsquare.gui.settings.SettingsController"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
<Label text="Settings"/>
|
||||
</Pane>
|
89
src/main/java/io/bitsquare/gui/trade/TradeController.java
Normal file
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
7
src/main/java/io/bitsquare/gui/trade/TradeView.fxml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.TabPane?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<TabPane fx:id="tabPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
|
||||
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="io.bitsquare.gui.trade.TradeController"/>
|
@ -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<String>()
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
|
||||
{
|
||||
setVolume();
|
||||
}
|
||||
});
|
||||
|
||||
price.textProperty().addListener(new ChangeListener<String>()
|
||||
{
|
||||
@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<Currency> currencies = orderBookFilterSettings.getCurrencies();
|
||||
Currency currency = orderBookFilterSettings.getCurrency();
|
||||
ComboBox currencyComboBox = createCurrencyItem("Currency: ", currency, currencies);
|
||||
currencyComboBox.valueProperty().addListener(new ChangeListener<Currency>()
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue ov, Currency oldValue, Currency newValue)
|
||||
{
|
||||
orderBookFilterSettings.setCurrency(newValue);
|
||||
}
|
||||
});
|
||||
|
||||
Label bankLabel = createFilterItem("Bank transfer types: ", "SEPA, OKPAY");
|
||||
|
||||
Label countriesLabel = createFilterItem("Countries: ", "DE, GB, AT");
|
||||
Label languagesLabel = createFilterItem("Languages: ", "DE, EN");
|
||||
Label arbitratorsLabel = createFilterItem("Arbitrators: ", "Paysty, BitRated");
|
||||
Label identityLabel = createFilterItem("Identity verifications: ", "Passport, Google+, Facebook, Skype");
|
||||
TextField collateralLabel = createCollateralItem("Collateral (%): ", 10);
|
||||
}
|
||||
|
||||
private ComboBox createCurrencyItem(String labelText, Currency currency, ArrayList<Currency> currencies)
|
||||
{
|
||||
final Separator separator = new Separator();
|
||||
separator.setPrefWidth(380);
|
||||
separator.setLayoutY(0 + filterPaneItemOffset);
|
||||
separator.setLayoutX(0);
|
||||
final Label label = new Label(labelText);
|
||||
label.setLayoutY(10 + filterPaneItemOffset);
|
||||
ObservableList<Currency> options = FXCollections.observableArrayList(currencies);
|
||||
final ComboBox comboBox = new ComboBox(options);
|
||||
comboBox.setLayoutX(70);
|
||||
comboBox.setLayoutY(5 + filterPaneItemOffset);
|
||||
comboBox.setValue(currency);
|
||||
|
||||
|
||||
detailsPane.getChildren().addAll(separator, label, comboBox);
|
||||
filterPaneItemOffset += 40;
|
||||
return comboBox;
|
||||
}
|
||||
|
||||
private Label createFilterItem(String labelText, String valueText)
|
||||
{
|
||||
final Separator separator = new Separator();
|
||||
separator.setPrefWidth(380);
|
||||
separator.setLayoutY(0 + filterPaneItemOffset);
|
||||
separator.setLayoutX(0);
|
||||
final Label label = new Label(labelText + valueText);
|
||||
label.setLayoutY(10 + filterPaneItemOffset);
|
||||
label.setPrefWidth(310);
|
||||
Tooltip tooltip = new Tooltip(valueText);
|
||||
label.setTooltip(tooltip);
|
||||
|
||||
final Button edit = new Button("Edit");
|
||||
edit.setPrefWidth(50);
|
||||
edit.setLayoutX(330);
|
||||
edit.setLayoutY(5 + filterPaneItemOffset);
|
||||
|
||||
detailsPane.getChildren().addAll(separator, label, edit);
|
||||
filterPaneItemOffset += 40;
|
||||
return label;
|
||||
}
|
||||
|
||||
private TextField createCollateralItem(String labelText, double collateral)
|
||||
{
|
||||
final Separator separator = new Separator();
|
||||
separator.setPrefWidth(380);
|
||||
separator.setLayoutY(0 + filterPaneItemOffset);
|
||||
separator.setLayoutX(0);
|
||||
final Label label = new Label(labelText);
|
||||
label.setLayoutY(10 + filterPaneItemOffset);
|
||||
label.setPrefWidth(310);
|
||||
|
||||
final TextField collateralValue = new TextField(Double.toString(collateral));
|
||||
collateralValue.setLayoutX(90);
|
||||
collateralValue.setLayoutY(5 + filterPaneItemOffset);
|
||||
collateralValue.setPrefWidth(50);
|
||||
|
||||
detailsPane.getChildren().addAll(separator, label, collateralValue);
|
||||
filterPaneItemOffset += 40;
|
||||
|
||||
return collateralValue;
|
||||
}
|
||||
|
||||
|
||||
private double textInputToNumber(String oldValue, String newValue)
|
||||
{
|
||||
//TODO use regex.... or better custom textfield component
|
||||
double d = 0.0;
|
||||
if (!newValue.equals(""))
|
||||
{
|
||||
d = Converter.convertToDouble(newValue);
|
||||
if (d == Double.NEGATIVE_INFINITY)
|
||||
{
|
||||
amount.setText(oldValue);
|
||||
d = Converter.convertToDouble(oldValue);
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
private void setVolume()
|
||||
{
|
||||
double a = textInputToNumber(amount.getText(), amount.getText());
|
||||
double p = textInputToNumber(price.getText(), price.getText());
|
||||
volume.setText(Formatter.formatPrice(a * p));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
<AnchorPane fx:id="holderPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
|
||||
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="io.bitsquare.gui.trade.offer.CreateOfferController">
|
||||
<children>
|
||||
<HBox prefHeight="22.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0">
|
||||
<children>
|
||||
<ImageView fx:id="directionImageView"/>
|
||||
|
||||
<Label fx:id="buyLabel" text="Buy">
|
||||
<padding>
|
||||
<Insets left="4.0" right="4.0" top="5.0"/>
|
||||
</padding>
|
||||
</Label>
|
||||
|
||||
<TextField fx:id="amount" prefHeight="26.0" prefWidth="70.0" alignment="CENTER_RIGHT">
|
||||
<HBox.margin>
|
||||
<Insets left="0.0"/>
|
||||
</HBox.margin>
|
||||
</TextField>
|
||||
<Label text="BTC for">
|
||||
<padding>
|
||||
<Insets left="4.0" right="4.0" top="5.0"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<TextField fx:id="price" prefHeight="26.0" prefWidth="70.0" alignment="CENTER_RIGHT"/>
|
||||
<Label text="EUR =">
|
||||
<padding>
|
||||
<Insets left="4.0" right="4.0" top="5.0"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<TextField fx:id="volume" prefHeight="26.0" prefWidth="70.0" alignment="CENTER_RIGHT" editable="false"/>
|
||||
<Label prefHeight="21.0" text="EUR in total (Min. Amount:">
|
||||
<padding>
|
||||
<Insets left="4.0" right="4.0" top="5.0"/>
|
||||
</padding>
|
||||
<HBox.margin>
|
||||
<Insets/>
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
<TextField fx:id="minAmount" prefHeight="26.0" prefWidth="70.0" alignment="CENTER_RIGHT"/>
|
||||
<Label text="BTC)">
|
||||
<padding>
|
||||
<Insets left="4.0" right="4.0" top="5.0"/>
|
||||
</padding>
|
||||
</Label>
|
||||
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
<Pane fx:id="detailsPane" AnchorPane.topAnchor="50.0"
|
||||
AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0">
|
||||
|
||||
<Label text="Offer details:">
|
||||
<font>
|
||||
<Font size="18.0"/>
|
||||
</font>
|
||||
</Label>
|
||||
</Pane>
|
||||
|
||||
<Label text="Place offer" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="380.0">
|
||||
<font>
|
||||
<Font size="18.0"/>
|
||||
</font>
|
||||
</Label>
|
||||
<Separator AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="405.0"/>
|
||||
|
||||
<Label text="Offer fee: 0.01 BTC" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="415.0"/>
|
||||
<Button fx:id="placeOfferButton" text="Place offer" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="440.0"/>
|
||||
|
||||
</children>
|
||||
</AnchorPane>
|
@ -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<OrderBookListItem> 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<String>()
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
|
||||
{
|
||||
updateOfferList();
|
||||
}
|
||||
});
|
||||
|
||||
createFilterPane();
|
||||
|
||||
updateOfferList();
|
||||
|
||||
amount.textProperty().addListener(new ChangeListener<String>()
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
|
||||
{
|
||||
orderBookFilter.setAmount(textInputToNumber(oldValue, newValue));
|
||||
updateOfferList();
|
||||
updateVolume();
|
||||
}
|
||||
});
|
||||
|
||||
price.textProperty().addListener(new ChangeListener<String>()
|
||||
{
|
||||
@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));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<String> values, List<String> allValues)
|
||||
{
|
||||
final Pane pane = new Pane();
|
||||
pane.setPrefHeight(23);
|
||||
|
||||
final Label titleLabel = new Label(title);
|
||||
titleLabel.setLayoutY(4);
|
||||
titleLabel.setId("form-title");
|
||||
|
||||
FlowPane flowPane = new FlowPane();
|
||||
|
||||
double xPos = 170.0;
|
||||
double yPos = 5.0;
|
||||
|
||||
List<String> openValues = new ArrayList<>(allValues);
|
||||
openValues.removeAll(values);
|
||||
ObservableList<String> observableList = FXCollections.observableArrayList(openValues);
|
||||
Collections.sort(observableList);
|
||||
|
||||
ComboBox comboBox = new ComboBox(observableList);
|
||||
comboBox.setLayoutX(xPos);
|
||||
comboBox.setLayoutY(yPos);
|
||||
comboBox.setClip(Icons.getIconImageView(Icons.ADD));
|
||||
comboBox.setValue(Settings.getCurrency());
|
||||
|
||||
comboBox.valueProperty().addListener(new ChangeListener<Object>()
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue ov, Object oldValue, Object newValue)
|
||||
{
|
||||
if (newValue != null)
|
||||
{
|
||||
String value;
|
||||
if (newValue instanceof Currency)
|
||||
value = ((Currency) newValue).getCurrencyCode();
|
||||
else
|
||||
value = (String) newValue;
|
||||
|
||||
if (flowPane.getChildren().size() > 0)
|
||||
{
|
||||
Pane lastItem = (Pane) flowPane.getChildren().get(flowPane.getChildren().size() - 1);
|
||||
Button button = (Button) lastItem.getChildren().get(0);
|
||||
button.setText(button.getText().substring(0, button.getText().length() - 2) + ", ");
|
||||
}
|
||||
|
||||
addRemovableItem(flowPane, value + " ", observableList);
|
||||
comboBox.getSelectionModel().clearSelection();
|
||||
observableList.remove(newValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// combobox does not support icon (mask background with icon), so we need a graphic here
|
||||
ImageView addImageView = Icons.getIconImageView(Icons.ADD);
|
||||
addImageView.setLayoutX(xPos);
|
||||
addImageView.setLayoutY(yPos);
|
||||
addImageView.setMouseTransparent(true);
|
||||
|
||||
pane.getChildren().addAll(titleLabel, comboBox, addImageView);
|
||||
|
||||
Iterator<String> iterator = values.iterator();
|
||||
for (Iterator<String> stringIterator = iterator; stringIterator.hasNext(); )
|
||||
{
|
||||
String value = stringIterator.next();
|
||||
if (stringIterator.hasNext())
|
||||
addRemovableItem(flowPane, value + ", ", observableList);
|
||||
else
|
||||
addRemovableItem(flowPane, value + " ", observableList);
|
||||
}
|
||||
|
||||
parent.getChildren().addAll(pane, flowPane, new VSpacer(3), new Separator(), new VSpacer(10));
|
||||
}
|
||||
|
||||
private static void addRemovableItem(FlowPane flowPane, String text, ObservableList<String> observableList)
|
||||
{
|
||||
Pane pane = new Pane();
|
||||
|
||||
Button icon = new Button("", Icons.getIconImageView(Icons.REMOVE));
|
||||
icon.setStyle("-fx-background-color: transparent;");
|
||||
icon.setPadding(new Insets(-5.0, 0.0, 0.0, 0.0));
|
||||
icon.setVisible(false);
|
||||
|
||||
Button button = new Button(text);
|
||||
button.setStyle("-fx-background-color: transparent;");
|
||||
button.setPadding(new Insets(0.0, 0.0, 0.0, 0.0));
|
||||
|
||||
pane.setOnMouseEntered(e -> {
|
||||
icon.setVisible(true);
|
||||
icon.setLayoutX(button.getWidth() - 7);
|
||||
});
|
||||
pane.setOnMouseExited(e -> {
|
||||
icon.setVisible(false);
|
||||
icon.setLayoutX(0);
|
||||
});
|
||||
icon.setOnAction(e -> {
|
||||
flowPane.getChildren().remove(button.getParent());
|
||||
|
||||
observableList.add(text);
|
||||
Collections.sort(observableList);
|
||||
|
||||
if (flowPane.getChildren().size() > 0)
|
||||
{
|
||||
Pane lastItem = (Pane) flowPane.getChildren().get(flowPane.getChildren().size() - 1);
|
||||
Button lastButton = (Button) lastItem.getChildren().get(0);
|
||||
lastButton.setText(lastButton.getText().substring(0, lastButton.getText().length() - 2) + " ");
|
||||
}
|
||||
});
|
||||
pane.getChildren().addAll(button, icon);
|
||||
flowPane.getChildren().add(pane);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import io.bitsquare.gui.components.HSpacer?>
|
||||
<?import javafx.geometry.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.control.cell.PropertyValueFactory?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<AnchorPane fx:id="holderPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
|
||||
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="io.bitsquare.gui.trade.orderbook.OrderBookController">
|
||||
<children>
|
||||
|
||||
<HBox fx:id="topHBox" prefHeight="22.0" AnchorPane.topAnchor="10.0" AnchorPane.leftAnchor="10.0"
|
||||
AnchorPane.rightAnchor="10.0">
|
||||
<children>
|
||||
<Label text="Filter:" prefWidth="190" id="form-header-text"/>
|
||||
|
||||
<Button fx:id="tradeButton">
|
||||
<graphic>
|
||||
<ImageView fx:id="tradeButtonImageView"/>
|
||||
</graphic>
|
||||
</Button>
|
||||
<HSpacer prefWidth="10"/>
|
||||
<TextField fx:id="amount" prefHeight="26.0" prefWidth="60.0" alignment="CENTER_RIGHT">
|
||||
<HBox.margin>
|
||||
<Insets left="0.0"/>
|
||||
</HBox.margin>
|
||||
</TextField>
|
||||
<Label text="BTC for">
|
||||
<padding>
|
||||
<Insets left="4.0" right="4.0" top="5.0"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<TextField fx:id="price" prefHeight="26.0" prefWidth="70.0" alignment="CENTER_RIGHT"/>
|
||||
<Label text="EUR/BTC =">
|
||||
<padding>
|
||||
<Insets left="4.0" right="4.0" top="5.0"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<TextField fx:id="volume" prefHeight="26.0" prefWidth="70.0" alignment="CENTER_RIGHT" editable="false"/>
|
||||
<Label prefHeight="21.0" prefWidth="100.0" text="EUR in total">
|
||||
<padding>
|
||||
<Insets left="4.0" right="4.0" top="5.0"/>
|
||||
</padding>
|
||||
<HBox.margin>
|
||||
<Insets/>
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
<VBox fx:id="filterPane" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="40.0"
|
||||
AnchorPane.bottomAnchor="10.0" prefWidth="180.0">
|
||||
<Separator prefWidth="190"/>
|
||||
</VBox>
|
||||
|
||||
<TableView fx:id="orderBookTable" id="orderbook-table" AnchorPane.leftAnchor="200.0"
|
||||
AnchorPane.topAnchor="40.0" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="10.0">
|
||||
<columns>
|
||||
<TableColumn text="Amount (Min.)" fx:id="amountColumn" prefWidth="210">
|
||||
<cellValueFactory>
|
||||
<PropertyValueFactory property="amount"/>
|
||||
</cellValueFactory>
|
||||
</TableColumn>
|
||||
<TableColumn text="Price" fx:id="priceColumn" prefWidth="160">
|
||||
<cellValueFactory>
|
||||
<PropertyValueFactory property="price"/>
|
||||
</cellValueFactory>
|
||||
</TableColumn>
|
||||
<TableColumn text="Volume (Min.)" fx:id="volumeColumn" prefWidth="200">
|
||||
<cellValueFactory>
|
||||
<PropertyValueFactory property="volume"/>
|
||||
</cellValueFactory>
|
||||
</TableColumn>
|
||||
</columns>
|
||||
</TableView>
|
||||
|
||||
</children>
|
||||
</AnchorPane>
|
@ -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<ProcessStepItem> processStepItems = new ArrayList();
|
||||
private double requestedAmount;
|
||||
|
||||
private VBox vBox;
|
||||
private TitledPane offerDetailsTitlePane, contractTitlePane;
|
||||
private ProcessStepBar<String> 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);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.layout.*?>
|
||||
<AnchorPane fx:id="rootContainer"
|
||||
AnchorPane.leftAnchor="0.0"
|
||||
AnchorPane.rightAnchor="0.0"
|
||||
AnchorPane.topAnchor="0.0"
|
||||
AnchorPane.bottomAnchor="0.0"
|
||||
xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="io.bitsquare.gui.trade.tradeprocess.TradeProcessController"/>
|
13
src/main/java/io/bitsquare/gui/util/Colors.java
Normal file
@ -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");
|
||||
|
||||
}
|
24
src/main/java/io/bitsquare/gui/util/Converter.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
126
src/main/java/io/bitsquare/gui/util/Formatter.java
Normal file
@ -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<String> 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 + "%";
|
||||
}
|
||||
|
||||
}
|
33
src/main/java/io/bitsquare/gui/util/Icons.java
Normal file
@ -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)));
|
||||
}
|
||||
}
|
71
src/main/java/io/bitsquare/gui/util/Loc.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
35
src/main/java/io/bitsquare/gui/util/Utils.java
Normal file
@ -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<AnimationTimer, Void> 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();
|
||||
}
|
||||
}
|
||||
|
13
src/main/java/io/bitsquare/msg/IMessageFacade.java
Normal file
@ -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);
|
||||
}
|
60
src/main/java/io/bitsquare/msg/Message.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
28
src/main/java/io/bitsquare/msg/MessageFacade.java
Normal file
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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<Currency> 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<Currency> getCurrencies()
|
||||
{
|
||||
ArrayList<Currency> currencies = new ArrayList<>();
|
||||
currencies.add(Currency.getInstance("USD"));
|
||||
currencies.add(Currency.getInstance("EUR"));
|
||||
currencies.add(Currency.getInstance("CNY"));
|
||||
currencies.add(Currency.getInstance("RUB"));
|
||||
|
||||
currencies.add(Currency.getInstance("JPY"));
|
||||
currencies.add(Currency.getInstance("GBP"));
|
||||
currencies.add(Currency.getInstance("CAD"));
|
||||
currencies.add(Currency.getInstance("AUD"));
|
||||
currencies.add(Currency.getInstance("CHF"));
|
||||
currencies.add(Currency.getInstance("CNY"));
|
||||
|
||||
Set<Currency> otherCurrenciesSet = Currency.getAvailableCurrencies();
|
||||
ArrayList<Currency> otherCurrenciesList = new ArrayList<>();
|
||||
otherCurrenciesList.addAll(otherCurrenciesSet);
|
||||
Collections.sort(otherCurrenciesList, new CurrencyComparator());
|
||||
|
||||
currencies.addAll(otherCurrenciesList);
|
||||
return currencies;
|
||||
}
|
||||
|
||||
public Currency getCurrency()
|
||||
{
|
||||
return currency;
|
||||
}
|
||||
|
||||
public void setCurrency(Currency currency)
|
||||
{
|
||||
this.currency = currency;
|
||||
storage.write("OrderBookFilterSettings.currency", currency);
|
||||
}
|
||||
}
|
||||
|
||||
class CurrencyComparator implements Comparator<Currency>
|
||||
{
|
||||
@Override
|
||||
public int compare(Currency a, Currency b)
|
||||
{
|
||||
return a.getCurrencyCode().compareTo(b.getCurrencyCode());
|
||||
}
|
||||
}
|
187
src/main/java/io/bitsquare/settings/Settings.java
Normal file
@ -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<Currency> getAllCurrencies()
|
||||
{
|
||||
ArrayList<Currency> currencies = new ArrayList<>();
|
||||
currencies.add(Currency.getInstance("USD"));
|
||||
currencies.add(Currency.getInstance("EUR"));
|
||||
currencies.add(Currency.getInstance("CNY"));
|
||||
currencies.add(Currency.getInstance("RUB"));
|
||||
|
||||
currencies.add(Currency.getInstance("JPY"));
|
||||
currencies.add(Currency.getInstance("GBP"));
|
||||
currencies.add(Currency.getInstance("CAD"));
|
||||
currencies.add(Currency.getInstance("AUD"));
|
||||
currencies.add(Currency.getInstance("CHF"));
|
||||
currencies.add(Currency.getInstance("CNY"));
|
||||
|
||||
/* Set<Currency> otherCurrenciesSet = Currency.getAvailableCurrencies();
|
||||
ArrayList<Currency> otherCurrenciesList = new ArrayList<>();
|
||||
otherCurrenciesList.addAll(otherCurrenciesSet);
|
||||
Collections.sort(otherCurrenciesList, new CurrencyComparator());
|
||||
|
||||
currencies.addAll(otherCurrenciesList); */
|
||||
return currencies;
|
||||
}
|
||||
|
||||
public ArrayList<String> getAllBankTransferTypes()
|
||||
{
|
||||
ArrayList<String> 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<String> getAllCountries()
|
||||
{
|
||||
ArrayList<String> 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<String> getAllCountries()
|
||||
{
|
||||
ArrayList<String> result = new ArrayList<>();
|
||||
for (Locale locale : Locale.getAvailableLocales())
|
||||
{
|
||||
result.add(locale.getDisplayCountry());
|
||||
}
|
||||
return result;
|
||||
} */
|
||||
|
||||
/*public ArrayList<String> getAllLanguages()
|
||||
{
|
||||
ArrayList<String> result = new ArrayList<>();
|
||||
for (Locale locale : Locale.getAvailableLocales())
|
||||
{
|
||||
result.add(locale.getDisplayLanguage());
|
||||
}
|
||||
|
||||
return result;
|
||||
} */
|
||||
public ArrayList<String> getAllLanguages()
|
||||
{
|
||||
ArrayList<String> 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<String> getAllArbitrators()
|
||||
{
|
||||
ArrayList<String> 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<String> getAllIdentityVerifications()
|
||||
{
|
||||
ArrayList<String> identityVerifications = new ArrayList<>();
|
||||
identityVerifications.add("Passport");
|
||||
identityVerifications.add("PGP");
|
||||
identityVerifications.add("BTC-OTC");
|
||||
identityVerifications.add("Bitcointalk");
|
||||
identityVerifications.add("Reddit");
|
||||
identityVerifications.add("Skype");
|
||||
identityVerifications.add("Google+");
|
||||
identityVerifications.add("Twitter");
|
||||
identityVerifications.add("Diaspora");
|
||||
identityVerifications.add("Facebook");
|
||||
identityVerifications.add("Jabber");
|
||||
identityVerifications.add("Other");
|
||||
identityVerifications.add("Any");
|
||||
identityVerifications.add("None");
|
||||
return identityVerifications;
|
||||
}
|
||||
|
||||
public ArrayList<String> getAllCollaterals()
|
||||
{
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add("0.01");
|
||||
list.add("0.1");
|
||||
list.add("0.5");
|
||||
list.add("1.0");
|
||||
return list;
|
||||
}
|
||||
|
||||
public void setCurrency(Currency currency)
|
||||
{
|
||||
Settings.currency = currency;
|
||||
storage.write("Settings.currency", currency);
|
||||
}
|
||||
|
||||
|
||||
public void setLocale(Locale locale)
|
||||
{
|
||||
Settings.locale = locale;
|
||||
}
|
||||
|
||||
public OrderBookFilter getOrderBookFilter()
|
||||
{
|
||||
return orderBookFilter;
|
||||
}
|
||||
|
||||
}
|
6
src/main/java/io/bitsquare/setup/ISetup.java
Normal file
@ -0,0 +1,6 @@
|
||||
package io.bitsquare.setup;
|
||||
|
||||
public interface ISetup
|
||||
{
|
||||
void applyPersistedData();
|
||||
}
|
59
src/main/java/io/bitsquare/setup/MockSetup.java
Normal file
@ -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());
|
||||
|
||||
|
||||
}
|
||||
}
|
8
src/main/java/io/bitsquare/storage/IStorage.java
Normal file
@ -0,0 +1,8 @@
|
||||
package io.bitsquare.storage;
|
||||
|
||||
public interface IStorage
|
||||
{
|
||||
void write(String key, Object value);
|
||||
|
||||
Object read(String key);
|
||||
}
|
95
src/main/java/io/bitsquare/storage/SimpleStorage.java
Normal file
@ -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<String, Object>();
|
||||
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<String, Object> dict;
|
||||
}
|
78
src/main/java/io/bitsquare/trade/Contract.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
6
src/main/java/io/bitsquare/trade/Direction.java
Normal file
@ -0,0 +1,6 @@
|
||||
package io.bitsquare.trade;
|
||||
|
||||
public enum Direction
|
||||
{
|
||||
BUY, SELL
|
||||
}
|
129
src/main/java/io/bitsquare/trade/Offer.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
58
src/main/java/io/bitsquare/trade/OfferConstraints.java
Normal file
@ -0,0 +1,58 @@
|
||||
package io.bitsquare.trade;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OfferConstraints
|
||||
{
|
||||
private double collateral;
|
||||
private List<String> countries;
|
||||
private List<String> languages;
|
||||
private List<String> bankTransferTypes;
|
||||
private String arbitrator;
|
||||
private String identityVerification;
|
||||
|
||||
public OfferConstraints(List<String> countries,
|
||||
List<String> languages,
|
||||
double collateral,
|
||||
List<String> 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<String> getCountries()
|
||||
{
|
||||
return countries;
|
||||
}
|
||||
|
||||
public List<String> getLanguages()
|
||||
{
|
||||
return languages;
|
||||
}
|
||||
|
||||
public List<String> getBankTransferTypes()
|
||||
{
|
||||
return bankTransferTypes;
|
||||
}
|
||||
|
||||
public String getArbitrator()
|
||||
{
|
||||
return arbitrator;
|
||||
}
|
||||
|
||||
public String getIdentityVerification()
|
||||
{
|
||||
return identityVerification;
|
||||
}
|
||||
}
|
86
src/main/java/io/bitsquare/trade/Trade.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
177
src/main/java/io/bitsquare/trade/TradingFacade.java
Normal file
@ -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<String, Offer> offers = new HashMap<>();
|
||||
private final HashMap<String, Trade> trades = new HashMap<>();
|
||||
private final HashMap<String, Contract> 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<String, Trade> 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());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package io.bitsquare.trade.orderbook;
|
||||
|
||||
import io.bitsquare.gui.trade.orderbook.OrderBookListItem;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
public interface IOrderBook
|
||||
{
|
||||
ObservableList<OrderBookListItem> getFilteredList(OrderBookFilter orderBookFilter);
|
||||
}
|
205
src/main/java/io/bitsquare/trade/orderbook/MockOrderBook.java
Normal file
@ -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<OrderBookListItem> 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<OrderBookListItem> getFilteredList(OrderBookFilter orderBookFilter)
|
||||
{
|
||||
FilteredList filtered = orderBookListItems.filtered(new Predicate<OrderBookListItem>()
|
||||
{
|
||||
@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<OrderBookListItem> result = FXCollections.observableArrayList();
|
||||
result.addAll(filtered);
|
||||
return result;
|
||||
}
|
||||
|
||||
private OrderBookListItem getOfferListVO()
|
||||
{
|
||||
Offer i = getOffer();
|
||||
return new OrderBookListItem(i);
|
||||
}
|
||||
|
||||
public ArrayList<Currency> getCurrencies()
|
||||
{
|
||||
ArrayList<Currency> currencies = new ArrayList<>();
|
||||
currencies.add(Currency.getInstance("USD"));
|
||||
currencies.add(Currency.getInstance("EUR"));
|
||||
currencies.add(Currency.getInstance("CNY"));
|
||||
currencies.add(Currency.getInstance("RUB"));
|
||||
|
||||
currencies.add(Currency.getInstance("JPY"));
|
||||
currencies.add(Currency.getInstance("GBP"));
|
||||
currencies.add(Currency.getInstance("CAD"));
|
||||
currencies.add(Currency.getInstance("AUD"));
|
||||
currencies.add(Currency.getInstance("CHF"));
|
||||
currencies.add(Currency.getInstance("CNY"));
|
||||
|
||||
/* Set<Currency> otherCurrenciesSet = Currency.getAvailableCurrencies();
|
||||
ArrayList<Currency> otherCurrenciesList = new ArrayList<>();
|
||||
otherCurrenciesList.addAll(otherCurrenciesSet);
|
||||
Collections.sort(otherCurrenciesList, new CurrencyComparator());
|
||||
|
||||
currencies.addAll(otherCurrenciesList); */
|
||||
|
||||
return currencies;
|
||||
}
|
||||
|
||||
private Offer getOffer()
|
||||
{
|
||||
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<String> getCountries()
|
||||
{
|
||||
|
||||
return randomizeStrings(settings.getAllCountries(), false);
|
||||
}
|
||||
|
||||
private List<String> getLanguages()
|
||||
{
|
||||
return randomizeStrings(settings.getAllLanguages(), false);
|
||||
}
|
||||
|
||||
private List<String> getBankTransferTypes()
|
||||
{
|
||||
return randomizeStrings(settings.getAllBankTransferTypes(), false);
|
||||
}
|
||||
|
||||
private List<String> getArbitrators()
|
||||
{
|
||||
return randomizeStrings(settings.getAllArbitrators(), false);
|
||||
}
|
||||
|
||||
private List<String> getCollaterals()
|
||||
{
|
||||
return randomizeStrings(settings.getAllCollaterals(), false);
|
||||
}
|
||||
|
||||
|
||||
private List<String> randomizeStrings(List<String> list, boolean optional)
|
||||
{
|
||||
int e = new Random().nextInt(list.size());
|
||||
if (!optional && list.size() > 0)
|
||||
e = Math.max(e, 1);
|
||||
int s = (e == 0) ? 0 : new Random().nextInt(e);
|
||||
list = list.subList(s, e);
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<Double> randomizeDouble(List<Double> list, boolean optional)
|
||||
{
|
||||
int e = new Random().nextInt(list.size());
|
||||
if (!optional && list.size() > 0)
|
||||
e = Math.max(e, 1);
|
||||
int s = (e == 0) ? 0 : new Random().nextInt(e);
|
||||
list = list.subList(s, e);
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<Currency> randomizeCurrencies(List<Currency> list, boolean optional)
|
||||
{
|
||||
int e = new Random().nextInt(list.size());
|
||||
if (!optional && list.size() > 0)
|
||||
e = Math.max(e, 1);
|
||||
int s = (e == 0) ? 0 : new Random().nextInt(e);
|
||||
list = list.subList(s, e);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
class CurrencyComparator implements Comparator<Currency>
|
||||
{
|
||||
@Override
|
||||
public int compare(Currency a, Currency b)
|
||||
{
|
||||
return a.getCurrencyCode().compareTo(b.getCurrencyCode());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
|
||||
*/
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
61
src/main/java/io/bitsquare/user/BankDetails.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
74
src/main/java/io/bitsquare/user/User.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
43
src/main/java/io/bitsquare/util/Utils.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
6
src/main/resources/META-INF/MANIFEST.MF
Normal file
@ -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
|
0
src/main/resources/bitsquare.properties
Normal file
1
src/main/resources/i18n/displayStrings_de_DE.properties
Normal file
@ -0,0 +1 @@
|
||||
currency=Währung
|
1
src/main/resources/i18n/displayStrings_en_US.properties
Normal file
@ -0,0 +1 @@
|
||||
currency=Currency
|
BIN
src/main/resources/images/add.png
Normal file
After Width: | Height: | Size: 708 B |
BIN
src/main/resources/images/buy.png
Normal file
After Width: | Height: | Size: 264 B |
BIN
src/main/resources/images/buy_white.png
Normal file
After Width: | Height: | Size: 287 B |
BIN
src/main/resources/images/edit.png
Normal file
After Width: | Height: | Size: 425 B |
BIN
src/main/resources/images/edit_pen.png
Normal file
After Width: | Height: | Size: 415 B |
BIN
src/main/resources/images/funds.png
Normal file
After Width: | Height: | Size: 388 B |
BIN
src/main/resources/images/history.png
Normal file
After Width: | Height: | Size: 330 B |
BIN
src/main/resources/images/home.png
Normal file
After Width: | Height: | Size: 457 B |
BIN
src/main/resources/images/info.png
Normal file
After Width: | Height: | Size: 491 B |
BIN
src/main/resources/images/list.png
Normal file
After Width: | Height: | Size: 157 B |