mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-23 23:06:39 +01:00
Merge branch 'Development' into issue544-api
# Conflicts: # pom.xml
This commit is contained in:
commit
b040582f87
98 changed files with 1304 additions and 601 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -19,3 +19,9 @@ build
|
|||
.project
|
||||
.settings
|
||||
*.java.hsp
|
||||
*.~ava
|
||||
/bundles
|
||||
/Bitsquare*
|
||||
desktop.ini
|
||||
*.bat
|
||||
!package/windows/*bit*.bat
|
||||
|
|
|
@ -24,9 +24,9 @@ public class Version {
|
|||
private static final Logger log = LoggerFactory.getLogger(Version.class);
|
||||
|
||||
// The application versions
|
||||
public static final String VERSION = "0.4.9.6";
|
||||
public static final String VERSION = "0.4.9.6";
|
||||
|
||||
// The version nr. for the objects sent over the network. A change will break the serialization of old objects.
|
||||
// The version no. for the objects sent over the network. A change will break the serialization of old objects.
|
||||
// If objects are used for both network and database the network version is applied.
|
||||
// VERSION = 0.3.4 -> P2P_NETWORK_VERSION = 1
|
||||
// VERSION = 0.3.5 -> P2P_NETWORK_VERSION = 2
|
||||
|
@ -34,14 +34,14 @@ public class Version {
|
|||
// VERSION = 0.4.2 -> P2P_NETWORK_VERSION = 4
|
||||
public static final int P2P_NETWORK_VERSION = DevFlags.STRESS_TEST_MODE ? 100 : 4;
|
||||
|
||||
// The version nr. of the serialized data stored to disc. A change will break the serialization of old objects.
|
||||
// The version no. of the serialized data stored to disc. A change will break the serialization of old objects.
|
||||
// VERSION = 0.3.4 -> LOCAL_DB_VERSION = 1
|
||||
// VERSION = 0.3.5 -> LOCAL_DB_VERSION = 2
|
||||
// VERSION = 0.4.0 -> LOCAL_DB_VERSION = 3
|
||||
// VERSION = 0.4.2 -> LOCAL_DB_VERSION = 4
|
||||
public static final int LOCAL_DB_VERSION = 4;
|
||||
|
||||
// The version nr. of the current protocol. The offer holds that version.
|
||||
// The version no. of the current protocol. The offer holds that version.
|
||||
// A taker will check the version of the offers to see if his version is compatible.
|
||||
public static final int TRADE_PROTOCOL_VERSION = 1;
|
||||
private static int p2pMessageVersion;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package io.bitsquare.common;
|
||||
|
||||
import io.bitsquare.io.LookAheadObjectInputStream;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -26,15 +27,16 @@ public class ByteArrayUtils {
|
|||
private static final Logger log = LoggerFactory.getLogger(ByteArrayUtils.class);
|
||||
private static long lastTimeStamp = System.currentTimeMillis();
|
||||
|
||||
public static <T> T byteArrayToObject(byte[] data) {
|
||||
public static <T> T byteArrayToObject(byte[] data) throws IOException, ClassNotFoundException {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(data);
|
||||
ObjectInput in = null;
|
||||
Object result = null;
|
||||
try {
|
||||
in = new ObjectInputStream(bis);
|
||||
in = new LookAheadObjectInputStream(bis, true);
|
||||
result = in.readObject();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
} finally {
|
||||
try {
|
||||
bis.close();
|
||||
|
|
|
@ -210,7 +210,7 @@ public class Encryption {
|
|||
// Create a symmetric key
|
||||
SecretKey secretKey = generateSecretKey();
|
||||
|
||||
// Encrypt secretKey with receivers publicKey
|
||||
// Encrypt secretKey with receiver's publicKey
|
||||
byte[] encryptedSecretKey = encryptSecretKey(secretKey, encryptionPublicKey);
|
||||
|
||||
// Encrypt with sym key payload with appended hmac
|
||||
|
|
|
@ -28,7 +28,7 @@ public class Profiler {
|
|||
}
|
||||
|
||||
public static String printSystemLoadString() {
|
||||
return "System load: Memory (MB)): " + getUsedMemoryInMB() + " / Nr. of threads: " + Thread.activeCount();
|
||||
return "System load: Memory (MB)): " + getUsedMemoryInMB() + " / No. of threads: " + Thread.activeCount();
|
||||
}
|
||||
|
||||
public static long getUsedMemoryInMB() {
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.google.common.util.concurrent.ListeningExecutorService;
|
|||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import com.google.gson.*;
|
||||
import io.bitsquare.io.LookAheadObjectInputStream;
|
||||
import javafx.scene.input.Clipboard;
|
||||
import javafx.scene.input.ClipboardContent;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -210,7 +211,7 @@ public class Utilities {
|
|||
long free = runtime.freeMemory() / 1024 / 1024;
|
||||
long total = runtime.totalMemory() / 1024 / 1024;
|
||||
long used = total - free;
|
||||
log.info("System load (nr. threads/used memory (MB)): " + Thread.activeCount() + "/" + used);
|
||||
log.info("System load (no. threads/used memory (MB)): " + Thread.activeCount() + "/" + used);
|
||||
}
|
||||
|
||||
public static void copyToClipboard(String content) {
|
||||
|
@ -254,8 +255,8 @@ public class Utilities {
|
|||
try {
|
||||
ByteArrayInputStream byteInputStream =
|
||||
new ByteArrayInputStream(org.bitcoinj.core.Utils.parseAsHexOrBase58(serializedHexString));
|
||||
|
||||
try (ObjectInputStream objectInputStream = new ObjectInputStream(byteInputStream)) {
|
||||
|
||||
try (ObjectInputStream objectInputStream = new LookAheadObjectInputStream(byteInputStream)) {
|
||||
result = objectInputStream.readObject();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
|
@ -293,7 +294,7 @@ public class Utilities {
|
|||
ObjectInput in = null;
|
||||
Object result = null;
|
||||
try {
|
||||
in = new ObjectInputStream(bis);
|
||||
in = new LookAheadObjectInputStream(bis, true);
|
||||
result = in.readObject();
|
||||
if (!(result instanceof Serializable))
|
||||
throw new RuntimeException("Object not of type Serializable");
|
||||
|
@ -356,8 +357,7 @@ public class Utilities {
|
|||
}
|
||||
|
||||
|
||||
public static Object copy(Serializable orig) {
|
||||
Object obj = null;
|
||||
public static Object copy(Serializable orig) throws IOException, ClassNotFoundException {
|
||||
try {
|
||||
// Write the object out to a byte array
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
|
@ -368,12 +368,13 @@ public class Utilities {
|
|||
|
||||
// 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();
|
||||
ObjectInputStream in = new LookAheadObjectInputStream(new ByteArrayInputStream(bos.toByteArray()), true);
|
||||
Object obj = in.readObject();
|
||||
return obj;
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static String readTextFileFromServer(String url, String userAgent) throws IOException {
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package io.bitsquare.io;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Based on https://github.com/ikkisoft/SerialKiller but we removed the support for a config file as
|
||||
* that introduced many dependencies (like the vulnerable commons collections).
|
||||
*/
|
||||
public class LookAheadObjectInputStream extends ObjectInputStream {
|
||||
private static final Logger log = LoggerFactory.getLogger(LookAheadObjectInputStream.class);
|
||||
|
||||
// Covers classes used in the objects sent over the P2P network.
|
||||
// We don't add all particular classes as the risk to miss one (specially at updates) is too high and a package
|
||||
// based filter gives us sufficient security.
|
||||
// This white list is not sufficient for the objects used for local persistence! We don't use any white list for those.
|
||||
private static final Pattern[] whiteListP2PNetwork = {
|
||||
Pattern.compile("io\\.bitsquare\\..*$"),
|
||||
Pattern.compile("org\\.bitcoinj\\..*$"),
|
||||
|
||||
Pattern.compile("java\\.lang\\.Boolean$"),
|
||||
Pattern.compile("java\\.lang\\.Enum$"),
|
||||
Pattern.compile("java\\.lang\\.Integer$"),
|
||||
Pattern.compile("java\\.lang\\.Long$"),
|
||||
Pattern.compile("java\\.lang\\.Double$"),
|
||||
Pattern.compile("java\\.lang\\.Number$"),
|
||||
|
||||
Pattern.compile("java\\.util\\.ArrayList$"),
|
||||
Pattern.compile("java\\.util\\.Date$"),
|
||||
Pattern.compile("java\\.util\\.HashSet$"),
|
||||
Pattern.compile("java\\.util\\.HashMap$"),
|
||||
|
||||
// Type Signatures
|
||||
// https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html
|
||||
Pattern.compile("\\[B$") // byte array
|
||||
};
|
||||
|
||||
private final static Pattern[] blackList = {
|
||||
Pattern.compile("bsh\\.XThis$"),
|
||||
Pattern.compile("bsh\\.Interpreter$"),
|
||||
Pattern.compile("com\\.mchange\\.v2\\.c3p0\\.impl\\.PoolBackedDataSourceBase$"),
|
||||
Pattern.compile("org\\.apache\\.commons\\.beanutils\\.BeanComparator$"),
|
||||
Pattern.compile("org\\.apache\\.commons\\.collections\\.Transformer$"),
|
||||
Pattern.compile("org\\.apache\\.commons\\.collections\\.functors\\.InvokerTransformer$"),
|
||||
Pattern.compile("org\\.apache\\.commons\\.collections\\.functors\\.ChainedTransformer$"),
|
||||
Pattern.compile("org\\.apache\\.commons\\.collections\\.functors\\.ConstantTransformer$"),
|
||||
Pattern.compile("org\\.apache\\.commons\\.collections\\.functors\\.InstantiateTransformer$"),
|
||||
Pattern.compile("org\\.apache\\.commons\\.collections4\\.functors\\.InvokerTransformer$"),
|
||||
Pattern.compile("org\\.apache\\.commons\\.collections4\\.functors\\.ChainedTransformer$"),
|
||||
Pattern.compile("org\\.apache\\.commons\\.collections4\\.functors\\.ConstantTransformer$"),
|
||||
Pattern.compile("org\\.apache\\.commons\\.collections4\\.functors\\.InstantiateTransformer$"),
|
||||
Pattern.compile("org\\.apache\\.commons\\.collections4\\.comparators\\.TransformingComparator$"),
|
||||
Pattern.compile("org\\.apache\\.commons\\.fileupload\\.disk\\.DiskFileItem$"),
|
||||
Pattern.compile("org\\.apache\\.wicket\\.util\\.upload\\.DiskFileItem$"),
|
||||
Pattern.compile("org\\.codehaus\\.groovy\\.runtime\\.ConvertedClosure$"),
|
||||
Pattern.compile("org\\.codehaus\\.groovy\\.runtime\\.MethodClosure$"),
|
||||
Pattern.compile("org\\.hibernate\\.engine\\.spi\\.TypedValue$"),
|
||||
Pattern.compile("org\\.hibernate\\.tuple\\.component\\.AbstractComponentTuplizer$"),
|
||||
Pattern.compile("org\\.hibernate\\.tuple\\.component\\.PojoComponentTuplizer$"),
|
||||
Pattern.compile("org\\.hibernate\\.type\\.AbstractType$"),
|
||||
Pattern.compile("org\\.hibernate\\.type\\.ComponentType$"),
|
||||
Pattern.compile("org\\.hibernate\\.type\\.Type$"),
|
||||
Pattern.compile("com\\.sun\\.rowset\\.JdbcRowSetImpl$"),
|
||||
Pattern.compile("org\\.jboss\\.(weld\\.)?interceptor\\.builder\\.InterceptionModelBuilder$"),
|
||||
Pattern.compile("org\\.jboss\\.(weld\\.)?interceptor\\.builder\\.MethodReference$"),
|
||||
Pattern.compile("org\\.jboss\\.(weld\\.)?interceptor\\.proxy\\.DefaultInvocationContextFactory$"),
|
||||
Pattern.compile("org\\.jboss\\.(weld\\.)?interceptor\\.proxy\\.InterceptorMethodHandler$"),
|
||||
Pattern.compile("org\\.jboss\\.(weld\\.)?interceptor\\.reader\\.ClassMetadataInterceptorReference$"),
|
||||
Pattern.compile("org\\.jboss\\.(weld\\.)?interceptor\\.reader\\.DefaultMethodMetadata$"),
|
||||
Pattern.compile("org\\.jboss\\.(weld\\.)?interceptor\\.reader\\.ReflectiveClassMetadata$"),
|
||||
Pattern.compile("org\\.jboss\\.(weld\\.)?interceptor\\.reader\\.SimpleInterceptorMetadata$"),
|
||||
Pattern.compile("org\\.jboss\\.(weld\\.)?interceptor\\.spi\\.instance\\.InterceptorInstantiator$"),
|
||||
Pattern.compile("org\\.jboss\\.(weld\\.)?interceptor\\.spi\\.metadata\\.InterceptorReference$"),
|
||||
Pattern.compile("org\\.jboss\\.(weld\\.)?interceptor\\.spi\\.metadata\\.MethodMetadata$"),
|
||||
Pattern.compile("org\\.jboss\\.(weld\\.)?interceptor\\.spi\\.model\\.InterceptionModel$"),
|
||||
Pattern.compile("org\\.jboss\\.(weld\\.)?interceptor\\.spi\\.model\\.InterceptionType$"),
|
||||
Pattern.compile("java\\.rmi\\.registry\\.Registry$"),
|
||||
Pattern.compile("java\\.rmi\\.server\\.ObjID$"),
|
||||
Pattern.compile("java\\.rmi\\.server\\.RemoteObjectInvocationHandler$"),
|
||||
Pattern.compile("net\\.sf\\.json\\.JSONObject$"),
|
||||
Pattern.compile("javax\\.xml\\.transform\\.Templates$"),
|
||||
Pattern.compile("org\\.python\\.core\\.PyObject$"),
|
||||
Pattern.compile("org\\.python\\.core\\.PyBytecode$"),
|
||||
Pattern.compile("org\\.python\\.core\\.PyFunction$"),
|
||||
Pattern.compile("org\\.mozilla\\.javascript\\..*$"),
|
||||
Pattern.compile("org\\.apache\\.myfaces\\.context\\.servlet\\.FacesContextImpl$"),
|
||||
Pattern.compile("org\\.apache\\.myfaces\\.context\\.servlet\\.FacesContextImplBase$"),
|
||||
Pattern.compile("org\\.apache\\.myfaces\\.el\\.CompositeELResolver$"),
|
||||
Pattern.compile("org\\.apache\\.myfaces\\.el\\.unified\\.FacesELContext$"),
|
||||
Pattern.compile("org\\.apache\\.myfaces\\.view\\.facelets\\.el\\.ValueExpressionMethodExpression$"),
|
||||
Pattern.compile("com\\.sun\\.syndication\\.feed\\.impl\\.ObjectBean$"),
|
||||
Pattern.compile("org\\.springframework\\.beans\\.factory\\.ObjectFactory$"),
|
||||
Pattern.compile("org\\.springframework\\.core\\.SerializableTypeWrapper\\$MethodInvokeTypeProvider$"),
|
||||
Pattern.compile("org\\.springframework\\.aop\\.framework\\.AdvisedSupport$"),
|
||||
Pattern.compile("org\\.springframework\\.aop\\.target\\.SingletonTargetSource$"),
|
||||
Pattern.compile("org\\.springframework\\.aop\\.framework\\.JdkDynamicAopProxy$"),
|
||||
Pattern.compile("org\\.springframework\\.core\\.SerializableTypeWrapper\\$TypeProvider$"),
|
||||
Pattern.compile("java\\.util\\.PriorityQueue$"),
|
||||
Pattern.compile("java\\.lang\\.reflect\\.Proxy$"),
|
||||
Pattern.compile("java\\.util\\.Comparator$"),
|
||||
Pattern.compile("org\\.reflections\\.Reflections$"),
|
||||
|
||||
Pattern.compile("com\\.sun\\.org\\.apache\\.xalan\\.internal\\.xsltc\\.trax\\.TemplatesImpl$"),
|
||||
};
|
||||
private boolean useWhiteList;
|
||||
|
||||
|
||||
/**
|
||||
* @param inputStream The original inputStream
|
||||
* @throws IOException
|
||||
*/
|
||||
public LookAheadObjectInputStream(InputStream inputStream) throws IOException {
|
||||
this(inputStream, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param inputStream The original inputStream
|
||||
* @throws IOException
|
||||
*/
|
||||
public LookAheadObjectInputStream(InputStream inputStream, boolean useWhiteList) throws IOException {
|
||||
super(inputStream);
|
||||
|
||||
this.useWhiteList = useWhiteList;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
|
||||
String name = desc.getName();
|
||||
// log.error("resolveClass " + name);
|
||||
|
||||
for (Pattern pattern : blackList) {
|
||||
if (pattern.matcher(name).find()) {
|
||||
String msg = "We received a blacklisted class at Java deserialization: '" + name + "'" + "(regex pattern: " + pattern.toString() + ")";
|
||||
log.error(msg);
|
||||
throw new InvalidClassException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (useWhiteList) {
|
||||
boolean whiteListed = false;
|
||||
for (Pattern pattern : whiteListP2PNetwork) {
|
||||
if (pattern.matcher(name).find())
|
||||
whiteListed = true;
|
||||
}
|
||||
if (!whiteListed) {
|
||||
String msg = "We received a non-whitelisted class at Java deserialization: '" + name + "'";
|
||||
log.error(msg);
|
||||
throw new InvalidClassException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
return super.resolveClass(desc);
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ package io.bitsquare.storage;
|
|||
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.io.LookAheadObjectInputStream;
|
||||
import org.bitcoinj.core.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -103,7 +104,7 @@ public class FileManager<T> {
|
|||
public synchronized T read(File file) throws IOException, ClassNotFoundException {
|
||||
log.debug("read" + file);
|
||||
try (final FileInputStream fileInputStream = new FileInputStream(file);
|
||||
final ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) {
|
||||
final ObjectInputStream objectInputStream = new LookAheadObjectInputStream(fileInputStream, false)) {
|
||||
return (T) objectInputStream.readObject();
|
||||
} catch (Throwable t) {
|
||||
log.error("Exception at read: " + t.getMessage());
|
||||
|
|
|
@ -105,7 +105,7 @@ public abstract class BitsquareExecutable {
|
|||
parser.accepts(CoreOptionKeys.APP_DATA_DIR_KEY, description("Application data directory", DEFAULT_APP_DATA_DIR))
|
||||
.withRequiredArg();
|
||||
parser.accepts(CoreOptionKeys.IGNORE_DEV_MSG_KEY, description("If set to true all signed messages from Bitsquare developers are ignored " +
|
||||
"(Global alert, Version update alert, Filters for offers, nodes or payment account data)", false))
|
||||
"(Global alert, Version update alert, Filters for offers, nodes or trading account data)", false))
|
||||
.withRequiredArg()
|
||||
.ofType(boolean.class);
|
||||
parser.accepts(CoreOptionKeys.DUMP_STATISTICS, description("If set to true the trade statistics are stored as json file in the data dir.", false))
|
||||
|
|
|
@ -163,11 +163,19 @@ public class DisputeManager {
|
|||
else
|
||||
openDisputes.put(dispute.getTradeId(), dispute);
|
||||
});
|
||||
openDisputes.entrySet().stream().forEach(stringDisputeEntry -> {
|
||||
if (closedDisputes.containsKey(stringDisputeEntry.getKey())) {
|
||||
final Dispute dispute = stringDisputeEntry.getValue();
|
||||
dispute.setIsClosed(true);
|
||||
tradeManager.closeDisputedTrade(dispute.getTradeId());
|
||||
|
||||
// If we have duplicate disputes we close the second one (might happen if both traders opened a dispute and arbitrator
|
||||
// was offline, so could not forward msg to other peer, then the arbitrator might have 4 disputes open for 1 trade)
|
||||
openDisputes.entrySet().stream().forEach(openDisputeEntry -> {
|
||||
String key = openDisputeEntry.getKey();
|
||||
if (closedDisputes.containsKey(key)) {
|
||||
final Dispute closedDispute = closedDisputes.get(key);
|
||||
final Dispute openDispute = openDisputeEntry.getValue();
|
||||
// We need to check if is from the same peer, we don't want to close the peers dispute
|
||||
if (closedDispute.getTraderId() == openDispute.getTraderId()) {
|
||||
openDispute.setIsClosed(true);
|
||||
tradeManager.closeDisputedTrade(openDispute.getTradeId());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -557,10 +565,22 @@ public class DisputeManager {
|
|||
final Contract contract = dispute.getContract();
|
||||
|
||||
boolean isBuyer = keyRing.getPubKeyRing().equals(contract.getBuyerPubKeyRing());
|
||||
if ((isBuyer && disputeResult.getWinner() == DisputeResult.Winner.BUYER)
|
||||
|| (!isBuyer && disputeResult.getWinner() == DisputeResult.Winner.SELLER)
|
||||
|| (isBuyer && disputeResult.getWinner() == DisputeResult.Winner.STALE_MATE)) {
|
||||
DisputeResult.Winner publisher = disputeResult.getWinner();
|
||||
|
||||
// Sometimes the user who receives the trade amount is never online, so we might want to
|
||||
// let the loser publish the tx. When the winner comes online he gets his funds as it was published by the other peer.
|
||||
// Default isLoserPublisher is set to false
|
||||
if (disputeResult.isLoserPublisher()) {
|
||||
// we invert the logic
|
||||
if (publisher == DisputeResult.Winner.BUYER)
|
||||
publisher = DisputeResult.Winner.SELLER;
|
||||
else if (publisher == DisputeResult.Winner.SELLER)
|
||||
publisher = DisputeResult.Winner.BUYER;
|
||||
}
|
||||
|
||||
if ((isBuyer && publisher == DisputeResult.Winner.BUYER)
|
||||
|| (!isBuyer && publisher == DisputeResult.Winner.SELLER)
|
||||
|| (isBuyer && publisher == DisputeResult.Winner.STALE_MATE)) {
|
||||
|
||||
final Optional<Trade> tradeOptional = tradeManager.getTradeById(tradeId);
|
||||
Transaction payoutTx = null;
|
||||
|
@ -636,7 +656,7 @@ public class DisputeManager {
|
|||
} else {
|
||||
log.debug("We got a dispute result msg but we don't have a matching dispute. " +
|
||||
"That might happen when we get the disputeResultMessage before the dispute was created. " +
|
||||
"We try again after 1 sec. to apply the disputeResultMessage. TradeId = " + tradeId);
|
||||
"We try again after 2 sec. to apply the disputeResultMessage. TradeId = " + tradeId);
|
||||
if (!delayMsgMap.containsKey(uid)) {
|
||||
// We delay2 sec. to be sure the comm. msg gets added first
|
||||
Timer timer = UserThread.runAfter(() -> onDisputeResultMessage(disputeResultMessage), 2);
|
||||
|
|
|
@ -81,6 +81,7 @@ public final class DisputeResult implements Payload {
|
|||
private String arbitratorAddressAsString;
|
||||
private byte[] arbitratorPubKey;
|
||||
private long closeDate;
|
||||
private boolean isLoserPublisher;
|
||||
|
||||
transient private BooleanProperty tamperProofEvidenceProperty = new SimpleBooleanProperty();
|
||||
transient private BooleanProperty idVerificationProperty = new SimpleBooleanProperty();
|
||||
|
@ -245,6 +246,14 @@ public final class DisputeResult implements Payload {
|
|||
return winner;
|
||||
}
|
||||
|
||||
public void setLoserIsPublisher(boolean loserPublisher) {
|
||||
this.isLoserPublisher = loserPublisher;
|
||||
}
|
||||
|
||||
public boolean isLoserPublisher() {
|
||||
return isLoserPublisher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
|
|
@ -275,7 +275,7 @@ public class TradeWalletService {
|
|||
* @param takerRawTransactionInputs Raw data for the connected outputs for all inputs of the taker (normally 1 input)
|
||||
* @param takerChangeOutputValue Optional taker change output value
|
||||
* @param takerChangeAddressString Optional taker change address
|
||||
* @param offererAddressEntry The offerers address entry.
|
||||
* @param offererAddressEntry The offerer's address entry.
|
||||
* @param buyerPubKey The public key of the buyer.
|
||||
* @param sellerPubKey The public key of the seller.
|
||||
* @param arbitratorPubKey The public key of the arbitrator.
|
||||
|
@ -452,10 +452,10 @@ public class TradeWalletService {
|
|||
checkArgument(!buyerInputs.isEmpty());
|
||||
checkArgument(!sellerInputs.isEmpty());
|
||||
|
||||
// Check if offerers Multisig script is identical to the takers
|
||||
// Check if offerer's Multisig script is identical to the takers
|
||||
Script p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
|
||||
if (!offerersDepositTx.getOutput(0).getScriptPubKey().equals(p2SHMultiSigOutputScript))
|
||||
throw new TransactionVerificationException("Offerers p2SHMultiSigOutputScript does not match to takers p2SHMultiSigOutputScript");
|
||||
throw new TransactionVerificationException("Offerer's p2SHMultiSigOutputScript does not match to takers p2SHMultiSigOutputScript");
|
||||
|
||||
// The outpoints are not available from the serialized offerersDepositTx, so we cannot use that tx directly, but we use it to construct a new
|
||||
// depositTx
|
||||
|
@ -489,7 +489,7 @@ public class TradeWalletService {
|
|||
TransactionOutput offerersContractHashOutput = offerersDepositTx.getOutputs().get(1);
|
||||
log.debug("offerersContractHashOutput " + offerersContractHashOutput);
|
||||
if (!offerersContractHashOutput.getScriptPubKey().equals(contractHashOutput.getScriptPubKey()))
|
||||
throw new TransactionVerificationException("Offerers transaction output for the contract hash is not matching takers version.");
|
||||
throw new TransactionVerificationException("Offerer's transaction output for the contract hash is not matching takers version.");
|
||||
|
||||
// Add all outputs from offerersDepositTx to depositTx
|
||||
offerersDepositTx.getOutputs().forEach(depositTx::addOutput);
|
||||
|
|
|
@ -257,9 +257,9 @@ public class WalletService {
|
|||
walletAppKit.setLookaheadSize(500);
|
||||
|
||||
// Calculation is derived from: https://www.reddit.com/r/Bitcoin/comments/2vrx6n/privacy_in_bitcoinj_android_wallet_multibit_hive/coknjuz
|
||||
// Nr of false positives (56M keys in the blockchain):
|
||||
// No. of false positives (56M keys in the blockchain):
|
||||
// First attempt for FP rate:
|
||||
// FP rate = 0,0001; Nr of false positives: 0,0001 * 56 000 000 = 5600
|
||||
// FP rate = 0,0001; No. of false positives: 0,0001 * 56 000 000 = 5600
|
||||
// We have 1333keys: 1333 / (5600 + 1333) = 0.19 -> 19 % probability that a pub key is in our wallet
|
||||
// After tests I found out that the bandwidth consumption varies widely related to the generated filter.
|
||||
// About 20- 40 MB for upload and 30-130 MB for download at first start up (spv chain).
|
||||
|
@ -270,7 +270,7 @@ public class WalletService {
|
|||
// consumption.
|
||||
|
||||
// For now to reduce risks with high bandwidth consumption we reduce the FP rate by half.
|
||||
// FP rate = 0,00005; Nr of false positives: 0,00005 * 56 000 000 = 2800
|
||||
// FP rate = 0,00005; No. of false positives: 0,00005 * 56 000 000 = 2800
|
||||
// 1333 / (2800 + 1333) = 0.32 -> 32 % probability that a pub key is in our wallet
|
||||
walletAppKit.setBloomFilterFalsePositiveRate(0.00005);
|
||||
|
||||
|
@ -714,7 +714,7 @@ public class WalletService {
|
|||
public void doubleSpendTransaction(Transaction txToDoubleSpend, Address toAddress, Runnable resultHandler, ErrorMessageHandler errorMessageHandler) throws InsufficientMoneyException, AddressFormatException, AddressEntryException {
|
||||
final TransactionConfidence.ConfidenceType confidenceType = txToDoubleSpend.getConfidence().getConfidenceType();
|
||||
if (confidenceType == TransactionConfidence.ConfidenceType.PENDING) {
|
||||
log.debug("txToDoubleSpend nr. of inputs " + txToDoubleSpend.getInputs().size());
|
||||
log.debug("txToDoubleSpend no. of inputs " + txToDoubleSpend.getInputs().size());
|
||||
|
||||
Transaction newTransaction = new Transaction(params);
|
||||
txToDoubleSpend.getInputs().stream().forEach(input -> {
|
||||
|
@ -739,7 +739,7 @@ public class WalletService {
|
|||
}
|
||||
);
|
||||
|
||||
log.debug("newTransaction nr. of inputs " + newTransaction.getInputs().size());
|
||||
log.debug("newTransaction no. of inputs " + newTransaction.getInputs().size());
|
||||
log.debug("newTransaction size in kB " + newTransaction.bitcoinSerialize().length / 1024);
|
||||
|
||||
if (!newTransaction.getInputs().isEmpty()) {
|
||||
|
@ -1031,7 +1031,7 @@ public class WalletService {
|
|||
Wallet.SendRequest sendRequestForMultipleAddresses = getSendRequestForMultipleAddresses(fromAddresses, toAddress, amount, null, aesKey);
|
||||
Transaction tx = sendRequestForMultipleAddresses.tx;
|
||||
wallet.completeTx(sendRequestForMultipleAddresses);
|
||||
log.debug("Nr of inputs: " + tx.getInputs().size());
|
||||
log.debug("No. of inputs: " + tx.getInputs().size());
|
||||
int size = tx.bitcoinSerialize().length;
|
||||
log.debug("Tx size: " + size);
|
||||
return size;
|
||||
|
|
|
@ -179,7 +179,7 @@ public class PriceFeedService {
|
|||
}
|
||||
|
||||
} else {
|
||||
String errorMessage = "We don't have a price for currencyCode " + currencyCode;
|
||||
String errorMessage = "We don't have a price for " + currencyCode;
|
||||
log.debug(errorMessage);
|
||||
faultHandler.handleFault(errorMessage, new PriceRequestException(errorMessage));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package io.bitsquare.btc.pricefeed.providers;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.internal.LinkedTreeMap;
|
||||
import io.bitsquare.btc.pricefeed.MarketPrice;
|
||||
import io.bitsquare.http.HttpClient;
|
||||
import io.bitsquare.http.HttpException;
|
||||
import io.bitsquare.user.Preferences;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
// Using new BitcoinAverage API but we wait for an optimisation as the call contains much more data as we need and
|
||||
// the json is about 300kb instead od 30 kb in the old API.
|
||||
public class BitcoinAverage2PriceProvider extends PriceProvider {
|
||||
private static final Logger log = LoggerFactory.getLogger(BitcoinAverage2PriceProvider.class);
|
||||
|
||||
@Inject
|
||||
public BitcoinAverage2PriceProvider(HttpClient httpClient, Preferences preferences) {
|
||||
super(httpClient, preferences, "https://apiv2.bitcoinaverage.com/indices/global/ticker/", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, MarketPrice> getAllPrices() throws IOException, HttpException {
|
||||
Map<String, MarketPrice> marketPriceMap = new HashMap<>();
|
||||
LinkedTreeMap<String, Object> treeMap = new Gson().<LinkedTreeMap<String, Object>>fromJson(httpClient.requestWithGET("all"), LinkedTreeMap.class);
|
||||
Map<String, String> temp = new HashMap<>();
|
||||
treeMap.entrySet().stream().forEach(e -> {
|
||||
Object value = e.getValue();
|
||||
|
||||
// We need to check the type as we get an unexpected "timestamp" object at the end:
|
||||
if (value instanceof LinkedTreeMap) {
|
||||
LinkedTreeMap<String, Object> treeMap2 = (LinkedTreeMap) value;
|
||||
temp.clear();
|
||||
treeMap2.entrySet().stream().forEach(e2 -> temp.put(e2.getKey(), e2.getValue().toString()));
|
||||
String key = e.getKey().replace("BTC", "");
|
||||
marketPriceMap.put(key,
|
||||
new MarketPrice(key, temp.get("ask"), temp.get("bid"), temp.get("last")));
|
||||
}
|
||||
});
|
||||
return marketPriceMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MarketPrice getPrice(String currencyCode) throws IOException, HttpException {
|
||||
//Log.traceCall("currencyCode=" + currencyCode);
|
||||
JsonObject jsonObject = new JsonParser()
|
||||
.parse(httpClient.requestWithGET("BTC" + currencyCode))
|
||||
.getAsJsonObject();
|
||||
return new MarketPrice(currencyCode,
|
||||
jsonObject.get("ask").getAsString(),
|
||||
jsonObject.get("bid").getAsString(),
|
||||
jsonObject.get("last").getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BitcoinAveragePriceProvider";
|
||||
}
|
||||
}
|
|
@ -29,7 +29,6 @@ import java.security.PublicKey;
|
|||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class Filter implements StoragePayload {
|
||||
|
@ -38,23 +37,20 @@ public final class Filter implements StoragePayload {
|
|||
private static final Logger log = LoggerFactory.getLogger(Filter.class);
|
||||
private static final long TTL = TimeUnit.DAYS.toMillis(21);
|
||||
|
||||
public final List<String> bannedNodeAddress;
|
||||
public final List<String> bannedOfferIds;
|
||||
public final List<PaymentAccountFilter> bannedPaymentAccounts;
|
||||
public final ArrayList<String> bannedNodeAddress;
|
||||
public final ArrayList<String> bannedOfferIds;
|
||||
public final ArrayList<PaymentAccountFilter> bannedPaymentAccounts;
|
||||
private String signatureAsBase64;
|
||||
private transient PublicKey publicKey;
|
||||
private byte[] publicKeyBytes;
|
||||
|
||||
public Filter(List<String> bannedOfferIds, List<String> bannedNodeAddress, List<PaymentAccountFilter> bannedPaymentAccounts) {
|
||||
private transient PublicKey publicKey;
|
||||
|
||||
public Filter(ArrayList<String> bannedOfferIds, ArrayList<String> bannedNodeAddress, ArrayList<PaymentAccountFilter> bannedPaymentAccounts) {
|
||||
this.bannedOfferIds = bannedOfferIds;
|
||||
this.bannedNodeAddress = bannedNodeAddress;
|
||||
this.bannedPaymentAccounts = bannedPaymentAccounts;
|
||||
}
|
||||
|
||||
public Filter() {
|
||||
this(new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
try {
|
||||
in.defaultReadObject();
|
||||
|
|
|
@ -10,6 +10,7 @@ public class PaymentAccountFilter implements Serializable {
|
|||
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||
private static final Logger log = LoggerFactory.getLogger(PaymentAccountFilter.class);
|
||||
|
||||
public final String paymentMethodId;
|
||||
public final String getMethodName;
|
||||
public final String value;
|
||||
|
|
|
@ -120,7 +120,7 @@ public class BankUtil {
|
|||
case "CA":
|
||||
return "Transit Number:";
|
||||
default:
|
||||
return isBranchIdRequired(countryCode) ? "Branch nr.:" : "Branch nr. (optional):";
|
||||
return isBranchIdRequired(countryCode) ? "Branch no.:" : "Branch no. (optional):";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,7 @@ public class BankUtil {
|
|||
case "MX":
|
||||
return "CLABE:";
|
||||
default:
|
||||
return "Account nr. (e.g. IBAN):";
|
||||
return "Account no. (e.g. IBAN):";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -140,20 +140,17 @@ public class CountryUtil {
|
|||
return allCountries;
|
||||
}
|
||||
|
||||
// We use getAvailableLocales as we depend on display names (would be a bit painful with translations if handled
|
||||
// from a static list -or we find something ready made?).
|
||||
private static List<Locale> getAllCountryLocales() {
|
||||
List<Locale> allLocales = Arrays.asList(Locale.getAvailableLocales());
|
||||
Set<Locale> allLocalesAsSet = allLocales.stream().filter(locale -> !"".equals(locale.getCountry()))
|
||||
.map(locale -> new Locale("", locale.getCountry(), ""))
|
||||
List<Locale> allLocales = LocaleUtil.getAllLocales();
|
||||
|
||||
// Filter duplicate locale entries
|
||||
Set<Locale> allLocalesAsSet = allLocales.stream().filter(locale -> !locale.getCountry().isEmpty())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
allLocales = new ArrayList<>();
|
||||
allLocales.addAll(allLocalesAsSet);
|
||||
allLocales.add(new Locale("", "MD", "")); // Moldava
|
||||
allLocales.add(new Locale("", "KH", "")); // Cambodia
|
||||
allLocales.sort((locale1, locale2) -> locale1.getDisplayCountry().compareTo(locale2.getDisplayCountry()));
|
||||
return allLocales;
|
||||
List<Locale> allCountryLocales = new ArrayList<>();
|
||||
allCountryLocales.addAll(allLocalesAsSet);
|
||||
allCountryLocales.sort((locale1, locale2) -> locale1.getDisplayCountry().compareTo(locale2.getDisplayCountry()));
|
||||
return allCountryLocales;
|
||||
}
|
||||
|
||||
private static List<String> getNamesByCodes(List<String> countryCodes) {
|
||||
|
@ -164,7 +161,7 @@ public class CountryUtil {
|
|||
private static final String[] countryCodes = new String[]{"AE", "AL", "AR", "AT", "AU", "BA", "BE", "BG", "BH",
|
||||
"BO", "BR", "BY", "CA", "CH", "CL", "CN", "CO", "CR", "CS", "CU", "CY", "CZ", "DE", "DK", "DO", "DZ",
|
||||
"EC", "EE", "EG", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HR", "HU", "ID", "IE", "IL", "IN",
|
||||
"IQ", "IS", "IT", "JO", "JP", "KH", "KR", "KW", "LB", "LT", "LU", "LV", "LY", "MA", "MD", "ME", "MK", "MT", "MX",
|
||||
"IQ", "IS", "IT", "JO", "JP", "KE", "KH", "KR", "KW", "KZ", "LB", "LT", "LU", "LV", "LY", "MA", "MD", "ME", "MK", "MT", "MX",
|
||||
"MY", "NI", "NL", "NO", "NZ", "OM", "PA", "PE", "PH", "PL", "PR", "PT", "PY", "QA", "RO", "RS", "RU",
|
||||
"SA", "SD", "SE", "SG", "SI", "SK", "SV", "SY", "TH", "TN", "TR", "TW", "UA", "US", "UY", "VE", "VN",
|
||||
"YE", "ZA"};
|
||||
|
@ -173,7 +170,7 @@ public class CountryUtil {
|
|||
private static final String[] regionCodes = new String[]{"AS", "EU", "SA", "EU", "OC", "EU", "EU", "EU", "AS",
|
||||
"SA", "SA", "EU", "NA", "EU", "SA", "AS", "SA", "NA", "EU", "NA", "EU", "EU", "EU", "EU", "NA", "AF",
|
||||
"SA", "EU", "AF", "EU", "EU", "EU", "EU", "EU", "NA", "AS", "NA", "EU", "EU", "AS", "EU", "AS", "AS",
|
||||
"AS", "EU", "EU", "AS", "AS", "AS", "AS", "AS", "AS", "EU", "EU", "EU", "AF", "AF", "EU", "EU", "EU", "EU", "NA",
|
||||
"AS", "EU", "EU", "AS", "AS", "AF", "AS", "AS", "AS", "AS", "AS", "EU", "EU", "EU", "AF", "AF", "EU", "EU", "EU", "EU", "NA",
|
||||
"AS", "NA", "EU", "EU", "OC", "AS", "NA", "SA", "AS", "EU", "NA", "EU", "SA", "AS", "EU", "EU", "EU",
|
||||
"AS", "AF", "EU", "AS", "EU", "EU", "NA", "AS", "AS", "AF", "AS", "AS", "EU", "NA", "SA", "SA", "AS",
|
||||
"AS", "AF"};
|
||||
|
|
|
@ -74,93 +74,113 @@ public class CurrencyUtil {
|
|||
// https://forum.bitsquare.io/t/how-to-add-your-favorite-altcoin/
|
||||
public static List<CryptoCurrency> createAllSortedCryptoCurrenciesList() {
|
||||
final List<CryptoCurrency> result = new ArrayList<>();
|
||||
result.add(new CryptoCurrency("XMR", "Monero"));
|
||||
result.add(new CryptoCurrency("SC", "Siacoin"));
|
||||
result.add(new CryptoCurrency("ETH", "Ether"));
|
||||
result.add(new CryptoCurrency("ETC", "EtherClassic"));
|
||||
result.add(new CryptoCurrency("STEEM", "STEEM"));
|
||||
result.add(new CryptoCurrency("STEEMUSD", "Steem Dollars", true));
|
||||
result.add(new CryptoCurrency("FLO", "FlorinCoin"));
|
||||
result.add(new CryptoCurrency("MT", "Mycelium Token", true));
|
||||
result.add(new CryptoCurrency("XEM", "NEM"));
|
||||
result.add(new CryptoCurrency("LTC", "Litecoin"));
|
||||
|
||||
result.add(new CryptoCurrency("AIB", "Advanced Internet Blocks"));
|
||||
result.add(new CryptoCurrency("ANTI", "Anti"));
|
||||
result.add(new CryptoCurrency("ARG", "Argentum"));
|
||||
result.add(new CryptoCurrency("REP", "Augur", true));
|
||||
result.add(new CryptoCurrency("BATL", "Battlestars"));
|
||||
result.add(new CryptoCurrency("BIGUP", "BigUp"));
|
||||
result.add(new CryptoCurrency("BITAUD", "BitAUD", true));
|
||||
result.add(new CryptoCurrency("BITCHF", "BitCHF", true));
|
||||
result.add(new CryptoCurrency("BITCNY", "BitCNY", true));
|
||||
result.add(new CryptoCurrency("BITEUR", "BitEUR", true));
|
||||
result.add(new CryptoCurrency("BITGBP", "BitGBP", true));
|
||||
result.add(new CryptoCurrency("BITHKD", "BitHKD", true));
|
||||
result.add(new CryptoCurrency("BITNZD", "BitNZD", true));
|
||||
result.add(new CryptoCurrency("BITSEK", "BitSEK", true));
|
||||
result.add(new CryptoCurrency("BITSGD", "BitSGD", true));
|
||||
result.add(new CryptoCurrency("SYNQ", "BitSYNQ"));
|
||||
result.add(new CryptoCurrency("BTS", "BitShares"));
|
||||
result.add(new CryptoCurrency("BITUSD", "BitUSD", true));
|
||||
result.add(new CryptoCurrency("BLK", "Blackcoin"));
|
||||
result.add(new CryptoCurrency("BURST", "Burstcoin"));
|
||||
result.add(new CryptoCurrency("CLAM", "Clams"));
|
||||
result.add(new CryptoCurrency("CLOAK", "CloakCoin"));
|
||||
result.add(new CryptoCurrency("CMT", "Comet"));
|
||||
result.add(new CryptoCurrency("XCP", "Counterparty"));
|
||||
result.add(new CryptoCurrency("CRBIT", "Creditbit"));
|
||||
result.add(new CryptoCurrency("CBX", "Crypto Bullion"));
|
||||
result.add(new CryptoCurrency("DAO", "DAO", true));
|
||||
result.add(new CryptoCurrency("DIBC", "DIBCOIN"));
|
||||
result.add(new CryptoCurrency("DASH", "Dash"));
|
||||
result.add(new CryptoCurrency("DCR", "Decred"));
|
||||
result.add(new CryptoCurrency("DGB", "Digibyte"));
|
||||
result.add(new CryptoCurrency("DRS", "Digital Rupees"));
|
||||
result.add(new CryptoCurrency("DGD", "DigixDAO Tokens", true));
|
||||
result.add(new CryptoCurrency("DOGE", "Dogecoin"));
|
||||
result.add(new CryptoCurrency("DMC", "DynamicCoin"));
|
||||
result.add(new CryptoCurrency("EMC", "Emercoin"));
|
||||
result.add(new CryptoCurrency("EURT", "EUR Tether"));
|
||||
result.add(new CryptoCurrency("ESP", "Espers"));
|
||||
result.add(new CryptoCurrency("ENT", "Eternity"));
|
||||
result.add(new CryptoCurrency("ETH", "Ether"));
|
||||
result.add(new CryptoCurrency("ETC", "Ether Classic"));
|
||||
result.add(new CryptoCurrency("ERC", "Europecoin"));
|
||||
result.add(new CryptoCurrency("EGC", "EverGreenCoin"));
|
||||
result.add(new CryptoCurrency("FCT", "Factom"));
|
||||
result.add(new CryptoCurrency("FAIR", "FairCoin"));
|
||||
result.add(new CryptoCurrency("FLO", "FlorinCoin"));
|
||||
result.add(new CryptoCurrency("GEMZ", "Gemz"));
|
||||
result.add(new CryptoCurrency("GRC", "Gridcoin"));
|
||||
result.add(new CryptoCurrency("GRS", "Groestlcoin"));
|
||||
result.add(new CryptoCurrency("NLG", "Gulden"));
|
||||
result.add(new CryptoCurrency("HODL", "HOdlcoin"));
|
||||
result.add(new CryptoCurrency("HNC", "HunCoin"));
|
||||
result.add(new CryptoCurrency("IOC", "I/O Coin"));
|
||||
result.add(new CryptoCurrency("JPYT", "JPY Tether"));
|
||||
result.add(new CryptoCurrency("JBS", "Jumbucks"));
|
||||
result.add(new CryptoCurrency("LBC", "LBRY Credits"));
|
||||
result.add(new CryptoCurrency("LSK", "Lisk"));
|
||||
result.add(new CryptoCurrency("LTC", "Litecoin"));
|
||||
result.add(new CryptoCurrency("STR", "Lumen"));
|
||||
result.add(new CryptoCurrency("MAID", "MaidSafeCoin"));
|
||||
result.add(new CryptoCurrency("MKR", "Maker", true));
|
||||
result.add(new CryptoCurrency("MXT", "MarteXcoin"));
|
||||
result.add(new CryptoCurrency("MOIN", "Moin"));
|
||||
result.add(new CryptoCurrency("XMR", "Monero"));
|
||||
result.add(new CryptoCurrency("MT", "Mycelium Token", true));
|
||||
result.add(new CryptoCurrency("XMY", "Myriadcoin"));
|
||||
result.add(new CryptoCurrency("NAV", "Nav Coin"));
|
||||
result.add(new CryptoCurrency("XEM", "NEM"));
|
||||
result.add(new CryptoCurrency("NMC", "Namecoin"));
|
||||
result.add(new CryptoCurrency("NBT", "NuBits"));
|
||||
result.add(new CryptoCurrency("NSR", "NuShares"));
|
||||
result.add(new CryptoCurrency("SDC", "ShadowCash"));
|
||||
result.add(new CryptoCurrency("BTS", "BitShares"));
|
||||
result.add(new CryptoCurrency("BITUSD", "BitUSD", true));
|
||||
result.add(new CryptoCurrency("BITEUR", "BitEUR", true));
|
||||
result.add(new CryptoCurrency("BITCNY", "BitCNY", true));
|
||||
result.add(new CryptoCurrency("BITCHF", "BitCHF", true));
|
||||
result.add(new CryptoCurrency("BITGBP", "BitGBP", true));
|
||||
result.add(new CryptoCurrency("BITNZD", "BitNZD", true));
|
||||
result.add(new CryptoCurrency("BITAUD", "BitAUD", true));
|
||||
result.add(new CryptoCurrency("BITSGD", "BitSGD", true));
|
||||
result.add(new CryptoCurrency("BITHKD", "BitHKD", true));
|
||||
result.add(new CryptoCurrency("BITSEK", "BitSEK", true));
|
||||
result.add(new CryptoCurrency("PPC", "Peercoin"));
|
||||
result.add(new CryptoCurrency("XPM", "Primecoin"));
|
||||
result.add(new CryptoCurrency("SJCX", "StorjcoinX"));
|
||||
result.add(new CryptoCurrency("GEMZ", "Gemz"));
|
||||
result.add(new CryptoCurrency("DOGE", "Dogecoin"));
|
||||
result.add(new CryptoCurrency("BLK", "Blackcoin"));
|
||||
result.add(new CryptoCurrency("FCT", "Factom"));
|
||||
result.add(new CryptoCurrency("NXT", "Nxt"));
|
||||
result.add(new CryptoCurrency("XCP", "Counterparty"));
|
||||
result.add(new CryptoCurrency("XRP", "Ripple"));
|
||||
result.add(new CryptoCurrency("FAIR", "FairCoin"));
|
||||
result.add(new CryptoCurrency("MKR", "Maker", true));
|
||||
result.add(new CryptoCurrency("DGD", "DigixDAO Tokens", true));
|
||||
result.add(new CryptoCurrency("ANTI", "Anti"));
|
||||
result.add(new CryptoCurrency("VPN", "VPNCoin"));
|
||||
result.add(new CryptoCurrency("MAID", "MaidSafeCoin"));
|
||||
result.add(new CryptoCurrency("YBC", "YbCoin"));
|
||||
result.add(new CryptoCurrency("CLOAK", "CloakCoin"));
|
||||
result.add(new CryptoCurrency("EGC", "EverGreenCoin"));
|
||||
result.add(new CryptoCurrency("VRC", "VeriCoin"));
|
||||
result.add(new CryptoCurrency("ESP", "Espers"));
|
||||
result.add(new CryptoCurrency("XVG", "Verge"));
|
||||
result.add(new CryptoCurrency("XMY", "Myriadcoin"));
|
||||
result.add(new CryptoCurrency("MXT", "MarteXcoin"));
|
||||
result.add(new CryptoCurrency("GRS", "Groestlcoin"));
|
||||
result.add(new CryptoCurrency("IOC", "I/O Coin"));
|
||||
result.add(new CryptoCurrency("SIB", "Sibcoin"));
|
||||
result.add(new CryptoCurrency("CRBIT", "Creditbit"));
|
||||
result.add(new CryptoCurrency("BIGUP", "BigUp"));
|
||||
result.add(new CryptoCurrency("XPTX", "PlatinumBar"));
|
||||
result.add(new CryptoCurrency("JBS", "Jumbucks"));
|
||||
result.add(new CryptoCurrency("PINK", "Pinkcoin"));
|
||||
result.add(new CryptoCurrency("OK", "OKCash"));
|
||||
result.add(new CryptoCurrency("GRC", "Gridcoin"));
|
||||
result.add(new CryptoCurrency("MOIN", "Moin"));
|
||||
result.add(new CryptoCurrency("SLR", "SolarCoin"));
|
||||
result.add(new CryptoCurrency("SHIFT", "Shift"));
|
||||
result.add(new CryptoCurrency("ERC", "Europecoin"));
|
||||
result.add(new CryptoCurrency("POST", "PostCoin"));
|
||||
result.add(new CryptoCurrency("LSK", "Lisk"));
|
||||
result.add(new CryptoCurrency("USDT", "USD Tether"));
|
||||
result.add(new CryptoCurrency("EURT", "EUR Tether"));
|
||||
result.add(new CryptoCurrency("JPYT", "JPY Tether"));
|
||||
result.add(new CryptoCurrency("SYNX", "Syndicate"));
|
||||
result.add(new CryptoCurrency("WDC", "Worldcoin"));
|
||||
result.add(new CryptoCurrency("DAO", "DAO", true));
|
||||
result.add(new CryptoCurrency("CMT", "Comet"));
|
||||
result.add(new CryptoCurrency("SYNQ", "BitSYNQ"));
|
||||
result.add(new CryptoCurrency("LBC", "LBRY Credits"));
|
||||
result.add(new CryptoCurrency("HNC", "HunCoin"));
|
||||
result.add(new CryptoCurrency("UNO", "Unobtanium"));
|
||||
result.add(new CryptoCurrency("DGB", "Digibyte"));
|
||||
result.add(new CryptoCurrency("VCN", "VCoin"));
|
||||
result.add(new CryptoCurrency("DCR", "Decred"));
|
||||
result.add(new CryptoCurrency("CBX", "Crypto Bullion"));
|
||||
result.add(new CryptoCurrency("1CR", "1CRedit"));
|
||||
result.add(new CryptoCurrency("YACC", "YACCoin"));
|
||||
result.add(new CryptoCurrency("AIB", "Advanced Internet Blocks"));
|
||||
result.add(new CryptoCurrency("OPAL", "Opal"));
|
||||
result.add(new CryptoCurrency("PPC", "Peercoin"));
|
||||
result.add(new CryptoCurrency("PINK", "Pinkcoin"));
|
||||
result.add(new CryptoCurrency("XPTX", "PlatinumBar"));
|
||||
result.add(new CryptoCurrency("PLU", "Plutons", true));
|
||||
result.add(new CryptoCurrency("POST", "PostCoin"));
|
||||
result.add(new CryptoCurrency("XPM", "Primecoin"));
|
||||
result.add(new CryptoCurrency("XRP", "Ripple"));
|
||||
result.add(new CryptoCurrency("STEEM", "STEEM"));
|
||||
result.add(new CryptoCurrency("SDC", "ShadowCash"));
|
||||
result.add(new CryptoCurrency("SHIFT", "Shift"));
|
||||
result.add(new CryptoCurrency("SC", "Siacoin"));
|
||||
result.add(new CryptoCurrency("SF", "Siafund"));
|
||||
result.add(new CryptoCurrency("SIB", "Sibcoin"));
|
||||
result.add(new CryptoCurrency("SLR", "SolarCoin"));
|
||||
result.add(new CryptoCurrency("STEEMUSD", "Steem Dollars", true));
|
||||
result.add(new CryptoCurrency("SJCX", "StorjcoinX"));
|
||||
result.add(new CryptoCurrency("SYNX", "Syndicate"));
|
||||
result.add(new CryptoCurrency("AMP", "Synereo", true));
|
||||
|
||||
result.add(new CryptoCurrency("TRI", "Triangles"));
|
||||
result.add(new CryptoCurrency("USDT", "USD Tether"));
|
||||
result.add(new CryptoCurrency("UNO", "Unobtanium"));
|
||||
result.add(new CryptoCurrency("VCN", "VCoin"));
|
||||
result.add(new CryptoCurrency("VPN", "VPNCoin"));
|
||||
result.add(new CryptoCurrency("XVC", "Vcash"));
|
||||
result.add(new CryptoCurrency("XVG", "Verge"));
|
||||
result.add(new CryptoCurrency("VRC", "VeriCoin"));
|
||||
result.add(new CryptoCurrency("WDC", "Worldcoin"));
|
||||
result.add(new CryptoCurrency("YACC", "YACCoin"));
|
||||
result.add(new CryptoCurrency("YBC", "YbCoin"));
|
||||
result.add(new CryptoCurrency("ZEC", "Zcash"));
|
||||
result.add(new CryptoCurrency("XZC", "Zcoin"));
|
||||
|
||||
result.sort(TradeCurrency::compareTo);
|
||||
return result;
|
||||
}
|
||||
|
@ -168,11 +188,14 @@ public class CurrencyUtil {
|
|||
public static List<CryptoCurrency> getMainCryptoCurrencies() {
|
||||
final List<CryptoCurrency> result = new ArrayList<>();
|
||||
result.add(new CryptoCurrency("XMR", "Monero"));
|
||||
result.add(new CryptoCurrency("ZEC", "Zcash"));
|
||||
result.add(new CryptoCurrency("XZC", "Zcoin"));
|
||||
result.add(new CryptoCurrency("SC", "Siacoin"));
|
||||
result.add(new CryptoCurrency("ETH", "Ether"));
|
||||
result.add(new CryptoCurrency("ETC", "EtherClassic"));
|
||||
result.add(new CryptoCurrency("ETC", "Ether Classic"));
|
||||
result.add(new CryptoCurrency("STEEM", "STEEM"));
|
||||
result.add(new CryptoCurrency("MT", "Mycelium Token", true));
|
||||
result.add(new CryptoCurrency("REP", "Augur", true));
|
||||
result.add(new CryptoCurrency("FLO", "FlorinCoin"));
|
||||
result.add(new CryptoCurrency("LTC", "Litecoin"));
|
||||
result.add(new CryptoCurrency("DASH", "Dash"));
|
||||
|
|
|
@ -21,22 +21,27 @@ import io.bitsquare.user.Preferences;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class LanguageUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(LanguageUtil.class);
|
||||
|
||||
public static List<String> getAllLanguageCodes() {
|
||||
List<Locale> allLocales = Arrays.asList(Locale.getAvailableLocales());
|
||||
final Set<String> allLocaleCodesAsSet = allLocales.stream()
|
||||
.filter(locale -> !"".equals(locale.getLanguage()) && !"".equals(locale.getDisplayLanguage()))
|
||||
.map(locale -> new Locale(locale.getLanguage(), "").getLanguage())
|
||||
List<Locale> allLocales = LocaleUtil.getAllLocales();
|
||||
|
||||
// Filter duplicate locale entries
|
||||
Set<String> allLocalesAsSet = allLocales.stream().filter(locale -> !locale.getLanguage().isEmpty() && !locale.getDisplayLanguage().isEmpty())
|
||||
.map(locale -> locale.getLanguage())
|
||||
.collect(Collectors.toSet());
|
||||
List<String> allLocaleCodes = new ArrayList<>();
|
||||
allLocaleCodes.addAll(allLocaleCodesAsSet);
|
||||
allLocaleCodes.sort((o1, o2) -> getDisplayName(o1).compareTo(getDisplayName(o2)));
|
||||
return allLocaleCodes;
|
||||
|
||||
List<String> allLanguageCodes = new ArrayList<>();
|
||||
allLanguageCodes.addAll(allLocalesAsSet);
|
||||
allLanguageCodes.sort((o1, o2) -> getDisplayName(o1).compareTo(getDisplayName(o2)));
|
||||
return allLanguageCodes;
|
||||
}
|
||||
|
||||
public static String getDefaultLanguage() {
|
||||
|
|
201
core/src/main/java/io/bitsquare/locale/LocaleUtil.java
Normal file
201
core/src/main/java/io/bitsquare/locale/LocaleUtil.java
Normal file
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.locale;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class LocaleUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(LocaleUtil.class);
|
||||
|
||||
public static List<Locale> getAllLocales() {
|
||||
|
||||
// derived form Locale.getAvailableLocales() and added some missing locales
|
||||
List<Locale> allLocales = new ArrayList<>();
|
||||
|
||||
allLocales.add(new Locale("bg", "", ""));
|
||||
allLocales.add(new Locale("it", "", ""));
|
||||
allLocales.add(new Locale("ko", "", ""));
|
||||
allLocales.add(new Locale("uk", "", ""));
|
||||
allLocales.add(new Locale("lv", "", ""));
|
||||
allLocales.add(new Locale("pt", "", ""));
|
||||
allLocales.add(new Locale("sk", "", ""));
|
||||
allLocales.add(new Locale("ga", "", ""));
|
||||
allLocales.add(new Locale("et", "", ""));
|
||||
allLocales.add(new Locale("sv", "", ""));
|
||||
allLocales.add(new Locale("cs", "", ""));
|
||||
allLocales.add(new Locale("el", "", ""));
|
||||
allLocales.add(new Locale("hu", "", ""));
|
||||
allLocales.add(new Locale("in", "", ""));
|
||||
allLocales.add(new Locale("be", "", ""));
|
||||
allLocales.add(new Locale("es", "", ""));
|
||||
allLocales.add(new Locale("tr", "", ""));
|
||||
allLocales.add(new Locale("hr", "", ""));
|
||||
allLocales.add(new Locale("lt", "", ""));
|
||||
allLocales.add(new Locale("sq", "", ""));
|
||||
allLocales.add(new Locale("fr", "", ""));
|
||||
allLocales.add(new Locale("ja", "", ""));
|
||||
allLocales.add(new Locale("is", "", ""));
|
||||
allLocales.add(new Locale("de", "", ""));
|
||||
allLocales.add(new Locale("en", "", ""));
|
||||
allLocales.add(new Locale("ca", "", ""));
|
||||
allLocales.add(new Locale("sl", "", ""));
|
||||
allLocales.add(new Locale("fi", "", ""));
|
||||
allLocales.add(new Locale("mk", "", ""));
|
||||
allLocales.add(new Locale("sr", "", ""));
|
||||
allLocales.add(new Locale("th", "", ""));
|
||||
allLocales.add(new Locale("ar", "", ""));
|
||||
allLocales.add(new Locale("ru", "", ""));
|
||||
allLocales.add(new Locale("ms", "", ""));
|
||||
allLocales.add(new Locale("hi", "", ""));
|
||||
allLocales.add(new Locale("nl", "", ""));
|
||||
allLocales.add(new Locale("vi", "", ""));
|
||||
allLocales.add(new Locale("sr", "", ""));
|
||||
allLocales.add(new Locale("mt", "", ""));
|
||||
allLocales.add(new Locale("da", "", ""));
|
||||
allLocales.add(new Locale("ro", "", ""));
|
||||
allLocales.add(new Locale("no", "", ""));
|
||||
allLocales.add(new Locale("pl", "", ""));
|
||||
allLocales.add(new Locale("iw", "", ""));
|
||||
allLocales.add(new Locale("zh", "", ""));
|
||||
allLocales.add(new Locale("ar", "AE", ""));
|
||||
allLocales.add(new Locale("sq", "AL", ""));
|
||||
allLocales.add(new Locale("es", "AR", ""));
|
||||
allLocales.add(new Locale("de", "AT", ""));
|
||||
allLocales.add(new Locale("en", "AU", ""));
|
||||
allLocales.add(new Locale("sr", "BA", ""));
|
||||
allLocales.add(new Locale("sr", "BA", ""));
|
||||
allLocales.add(new Locale("fr", "BE", ""));
|
||||
allLocales.add(new Locale("nl", "BE", ""));
|
||||
allLocales.add(new Locale("bg", "BG", ""));
|
||||
allLocales.add(new Locale("ar", "BH", ""));
|
||||
allLocales.add(new Locale("es", "BO", ""));
|
||||
allLocales.add(new Locale("pt", "BR", ""));
|
||||
allLocales.add(new Locale("be", "BY", ""));
|
||||
allLocales.add(new Locale("fr", "CA", ""));
|
||||
allLocales.add(new Locale("en", "CA", ""));
|
||||
allLocales.add(new Locale("fr", "CH", ""));
|
||||
allLocales.add(new Locale("de", "CH", ""));
|
||||
allLocales.add(new Locale("it", "CH", ""));
|
||||
allLocales.add(new Locale("es", "CL", ""));
|
||||
allLocales.add(new Locale("zh", "CN", ""));
|
||||
allLocales.add(new Locale("es", "CO", ""));
|
||||
allLocales.add(new Locale("es", "CR", ""));
|
||||
allLocales.add(new Locale("sr", "CS", ""));
|
||||
allLocales.add(new Locale("es", "CU", ""));
|
||||
allLocales.add(new Locale("el", "CY", ""));
|
||||
allLocales.add(new Locale("cs", "CZ", ""));
|
||||
allLocales.add(new Locale("de", "DE", ""));
|
||||
allLocales.add(new Locale("da", "DK", ""));
|
||||
allLocales.add(new Locale("es", "DO", ""));
|
||||
allLocales.add(new Locale("ar", "DZ", ""));
|
||||
allLocales.add(new Locale("es", "EC", ""));
|
||||
allLocales.add(new Locale("et", "EE", ""));
|
||||
allLocales.add(new Locale("ar", "EG", ""));
|
||||
allLocales.add(new Locale("ca", "ES", ""));
|
||||
allLocales.add(new Locale("es", "ES", ""));
|
||||
allLocales.add(new Locale("fi", "FI", ""));
|
||||
allLocales.add(new Locale("fr", "FR", ""));
|
||||
allLocales.add(new Locale("en", "GB", ""));
|
||||
allLocales.add(new Locale("el", "GR", ""));
|
||||
allLocales.add(new Locale("de", "GR", ""));
|
||||
allLocales.add(new Locale("es", "GT", ""));
|
||||
allLocales.add(new Locale("zh", "HK", ""));
|
||||
allLocales.add(new Locale("es", "HN", ""));
|
||||
allLocales.add(new Locale("hr", "HR", ""));
|
||||
allLocales.add(new Locale("hu", "HU", ""));
|
||||
allLocales.add(new Locale("in", "ID", ""));
|
||||
allLocales.add(new Locale("ga", "IE", ""));
|
||||
allLocales.add(new Locale("en", "IE", ""));
|
||||
allLocales.add(new Locale("iw", "IL", ""));
|
||||
allLocales.add(new Locale("hi", "IN", ""));
|
||||
allLocales.add(new Locale("en", "IN", ""));
|
||||
allLocales.add(new Locale("ar", "IQ", ""));
|
||||
allLocales.add(new Locale("is", "IS", ""));
|
||||
allLocales.add(new Locale("it", "IT", ""));
|
||||
allLocales.add(new Locale("ar", "JO", ""));
|
||||
allLocales.add(new Locale("ja", "JP", ""));
|
||||
allLocales.add(new Locale("ja", "JP", ""));
|
||||
allLocales.add(new Locale("sw", "KE", ""));
|
||||
allLocales.add(new Locale("km", "KH", ""));
|
||||
allLocales.add(new Locale("ko", "KR", ""));
|
||||
allLocales.add(new Locale("ar", "KW", ""));
|
||||
allLocales.add(new Locale("kk", "KZ", ""));
|
||||
allLocales.add(new Locale("ar", "LB", ""));
|
||||
allLocales.add(new Locale("lt", "LT", ""));
|
||||
allLocales.add(new Locale("fr", "LU", ""));
|
||||
allLocales.add(new Locale("de", "LU", ""));
|
||||
allLocales.add(new Locale("lv", "LV", ""));
|
||||
allLocales.add(new Locale("ar", "LY", ""));
|
||||
allLocales.add(new Locale("ar", "MA", ""));
|
||||
allLocales.add(new Locale("ro", "MD", ""));
|
||||
allLocales.add(new Locale("sr", "ME", ""));
|
||||
allLocales.add(new Locale("sr", "ME", ""));
|
||||
allLocales.add(new Locale("mk", "MK", ""));
|
||||
allLocales.add(new Locale("mt", "MT", ""));
|
||||
allLocales.add(new Locale("en", "MT", ""));
|
||||
allLocales.add(new Locale("es", "MX", ""));
|
||||
allLocales.add(new Locale("ms", "MY", ""));
|
||||
allLocales.add(new Locale("es", "NI", ""));
|
||||
allLocales.add(new Locale("nl", "NL", ""));
|
||||
allLocales.add(new Locale("no", "NO", ""));
|
||||
allLocales.add(new Locale("no", "NO", ""));
|
||||
allLocales.add(new Locale("en", "NZ", ""));
|
||||
allLocales.add(new Locale("ar", "OM", ""));
|
||||
allLocales.add(new Locale("es", "PA", ""));
|
||||
allLocales.add(new Locale("es", "PE", ""));
|
||||
allLocales.add(new Locale("en", "PH", ""));
|
||||
allLocales.add(new Locale("pl", "PL", ""));
|
||||
allLocales.add(new Locale("es", "PR", ""));
|
||||
allLocales.add(new Locale("pt", "PT", ""));
|
||||
allLocales.add(new Locale("es", "PY", ""));
|
||||
allLocales.add(new Locale("ar", "QA", ""));
|
||||
allLocales.add(new Locale("ro", "RO", ""));
|
||||
allLocales.add(new Locale("sr", "RS", ""));
|
||||
allLocales.add(new Locale("sr", "RS", ""));
|
||||
allLocales.add(new Locale("ru", "RU", ""));
|
||||
allLocales.add(new Locale("ar", "SA", ""));
|
||||
allLocales.add(new Locale("ar", "SD", ""));
|
||||
allLocales.add(new Locale("sv", "SE", ""));
|
||||
allLocales.add(new Locale("en", "SG", ""));
|
||||
allLocales.add(new Locale("zh", "SG", ""));
|
||||
allLocales.add(new Locale("sl", "SI", ""));
|
||||
allLocales.add(new Locale("sk", "SK", ""));
|
||||
allLocales.add(new Locale("es", "SV", ""));
|
||||
allLocales.add(new Locale("ar", "SY", ""));
|
||||
allLocales.add(new Locale("th", "TH", ""));
|
||||
allLocales.add(new Locale("th", "TH", ""));
|
||||
allLocales.add(new Locale("ar", "TN", ""));
|
||||
allLocales.add(new Locale("tr", "TR", ""));
|
||||
allLocales.add(new Locale("zh", "TW", ""));
|
||||
allLocales.add(new Locale("uk", "UA", ""));
|
||||
allLocales.add(new Locale("en", "US", ""));
|
||||
allLocales.add(new Locale("es", "US", ""));
|
||||
allLocales.add(new Locale("es", "UY", ""));
|
||||
allLocales.add(new Locale("es", "VE", ""));
|
||||
allLocales.add(new Locale("vi", "VN", ""));
|
||||
allLocales.add(new Locale("ar", "YE", ""));
|
||||
allLocales.add(new Locale("en", "ZA", ""));
|
||||
|
||||
return allLocales;
|
||||
}
|
||||
}
|
|
@ -39,7 +39,7 @@ public final class AliPayAccountContractData extends PaymentAccountContractData
|
|||
|
||||
@Override
|
||||
public String getPaymentDetails() {
|
||||
return "AliPay - Account nr.: " + accountNr;
|
||||
return "AliPay - Account no.: " + accountNr;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,12 +48,12 @@ public final class ClearXchangeAccountContractData extends PaymentAccountContrac
|
|||
|
||||
@Override
|
||||
public String getPaymentDetails() {
|
||||
return "ClearXchange - Holder name: " + holderName + ", email or mobile nr.: " + emailOrMobileNr;
|
||||
return "ClearXchange - Holder name: " + holderName + ", email or mobile no.: " + emailOrMobileNr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentDetailsForTradePopup() {
|
||||
return "Holder name: " + holderName + "\n" +
|
||||
"Email or mobile nr.: " + emailOrMobileNr;
|
||||
"Email or mobile no.: " + emailOrMobileNr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public final class OKPayAccountContractData extends PaymentAccountContractData {
|
|||
|
||||
@Override
|
||||
public String getPaymentDetails() {
|
||||
return "OKPay - Account nr.: " + accountNr;
|
||||
return "OKPay - Account no.: " + accountNr;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -70,19 +70,19 @@ public final class PaymentMethod implements Persistable, Comparable {
|
|||
public static PaymentMethod BLOCK_CHAINS;
|
||||
|
||||
public static final List<PaymentMethod> ALL_VALUES = new ArrayList<>(Arrays.asList(
|
||||
OK_PAY = new PaymentMethod(OK_PAY_ID, 0, DAY, Coin.parseCoin("1.5")), // tx instant so min. wait time
|
||||
OK_PAY = new PaymentMethod(OK_PAY_ID, 0, DAY, Coin.parseCoin("2")), // tx instant so min. wait time
|
||||
SEPA = new PaymentMethod(SEPA_ID, 0, 8 * DAY, Coin.parseCoin("1")), // sepa takes 1-3 business days. We use 8 days to include safety for holidays
|
||||
FASTER_PAYMENTS = new PaymentMethod(FASTER_PAYMENTS_ID, 0, DAY, Coin.parseCoin("1")),
|
||||
CLEAR_X_CHANGE = new PaymentMethod(CLEAR_X_CHANGE_ID, 0, 8 * DAY, Coin.parseCoin("0.5")),
|
||||
SWISH = new PaymentMethod(SWISH_ID, 0, DAY, Coin.parseCoin("1.5")),
|
||||
CLEAR_X_CHANGE = new PaymentMethod(CLEAR_X_CHANGE_ID, 0, 8 * DAY, Coin.parseCoin("1")),
|
||||
SWISH = new PaymentMethod(SWISH_ID, 0, DAY, Coin.parseCoin("2")),
|
||||
NATIONAL_BANK = new PaymentMethod(NATIONAL_BANK_ID, 0, 4 * DAY, Coin.parseCoin("1")),
|
||||
SAME_BANK = new PaymentMethod(SAME_BANK_ID, 0, 2 * DAY, Coin.parseCoin("1")),
|
||||
SPECIFIC_BANKS = new PaymentMethod(SPECIFIC_BANKS_ID, 0, 4 * DAY, Coin.parseCoin("1")),
|
||||
PERFECT_MONEY = new PaymentMethod(PERFECT_MONEY_ID, 0, DAY, Coin.parseCoin("1")),
|
||||
ALI_PAY = new PaymentMethod(ALI_PAY_ID, 0, DAY, Coin.parseCoin("1.5")),
|
||||
CASH_DEPOSIT = new PaymentMethod(CASH_DEPOSIT_ID, 0, 6 * DAY, Coin.parseCoin("0.5")),
|
||||
US_POSTAL_MONEY_ORDER = new PaymentMethod(US_POSTAL_MONEY_ORDER_ID, 0, 6 * DAY, Coin.parseCoin("0.5")),
|
||||
BLOCK_CHAINS = new PaymentMethod(BLOCK_CHAINS_ID, 0, DAY, Coin.parseCoin("2"))
|
||||
ALI_PAY = new PaymentMethod(ALI_PAY_ID, 0, DAY, Coin.parseCoin("2")),
|
||||
CASH_DEPOSIT = new PaymentMethod(CASH_DEPOSIT_ID, 0, 6 * DAY, Coin.parseCoin("1")),
|
||||
US_POSTAL_MONEY_ORDER = new PaymentMethod(US_POSTAL_MONEY_ORDER_ID, 0, 6 * DAY, Coin.parseCoin("1")),
|
||||
BLOCK_CHAINS = new PaymentMethod(BLOCK_CHAINS_ID, 0, DAY, Coin.parseCoin("3"))
|
||||
));
|
||||
|
||||
private final String id;
|
||||
|
|
|
@ -39,7 +39,7 @@ public final class PerfectMoneyAccountContractData extends PaymentAccountContrac
|
|||
|
||||
@Override
|
||||
public String getPaymentDetails() {
|
||||
return "PerfectMoney - Account nr.: " + accountNr;
|
||||
return "PerfectMoney - Account no.: " + accountNr;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,12 +48,12 @@ public final class SwishAccountContractData extends PaymentAccountContractData {
|
|||
|
||||
@Override
|
||||
public String getPaymentDetails() {
|
||||
return "Swish - Holder name: " + holderName + ", mobile nr.: " + mobileNr;
|
||||
return "Swish - Holder name: " + holderName + ", mobile no.: " + mobileNr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentDetailsForTradePopup() {
|
||||
return "Holder name: " + holderName + "\n" +
|
||||
"Mobile nr.: " + mobileNr;
|
||||
"Mobile no.: " + mobileNr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
@Nullable
|
||||
transient private Storage<? extends TradableList> storage;
|
||||
transient protected TradeProtocol tradeProtocol;
|
||||
private transient Date maxTradePeriodDate, halfTradePeriodDate;
|
||||
transient private Date maxTradePeriodDate, halfTradePeriodDate;
|
||||
|
||||
// Immutable
|
||||
private final Offer offer;
|
||||
|
|
|
@ -239,7 +239,7 @@ public class TradeManager {
|
|||
trade.getDate(),
|
||||
(trade.getDepositTx() != null ? trade.getDepositTx().getHashAsString() : ""),
|
||||
keyRing.getPubKeyRing());
|
||||
tradeStatisticsManager.add(tradeStatistics);
|
||||
tradeStatisticsManager.add(tradeStatistics, true);
|
||||
|
||||
// We only republish trades from last 10 days
|
||||
// TODO check if needed at all. Don't want to remove it atm to not risk anything.
|
||||
|
|
|
@ -422,7 +422,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
|||
|
||||
double factor = (double) takersTradePrice / (double) offerPriceAsFiat.value;
|
||||
// We allow max. 2 % difference between own offer price calculation and takers calculation.
|
||||
// Market price might be different at offerers and takers side so we need a bit of tolerance.
|
||||
// Market price might be different at offerer's and takers side so we need a bit of tolerance.
|
||||
// The tolerance will get smaller once we have multiple price feeds avoiding fast price fluctuations
|
||||
// from one provider.
|
||||
if (Math.abs(1 - factor) > 0.02) {
|
||||
|
|
|
@ -458,7 +458,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
() -> {
|
||||
if (!stopped) {
|
||||
log.debug("Successful added offer to P2P network");
|
||||
// Refresh means we send only the dat needed to refresh the TTL (hash, signature and sequence nr.)
|
||||
// Refresh means we send only the dat needed to refresh the TTL (hash, signature and sequence no.)
|
||||
if (periodicRefreshOffersTimer == null)
|
||||
startPeriodicRefreshOffersTimer();
|
||||
} else {
|
||||
|
|
|
@ -52,7 +52,7 @@ public class ProcessPayDepositRequest extends TradeTask {
|
|||
PaymentAccountContractData paymentAccountContractData = checkNotNull(payDepositRequest.takerPaymentAccountContractData);
|
||||
final PaymentAccountFilter[] appliedPaymentAccountFilter = new PaymentAccountFilter[1];
|
||||
if (processModel.isPeersPaymentAccountDataAreBanned(paymentAccountContractData, appliedPaymentAccountFilter)) {
|
||||
failed("Other trader is banned by his payment account data.\n" +
|
||||
failed("Other trader is banned by his trading account data.\n" +
|
||||
"paymentAccountContractData=" + paymentAccountContractData.getPaymentDetails() + "\n" +
|
||||
"banFilter=" + appliedPaymentAccountFilter[0].toString());
|
||||
return;
|
||||
|
|
|
@ -50,7 +50,7 @@ public class ProcessPublishDepositTxRequest extends TradeTask {
|
|||
PaymentAccountContractData paymentAccountContractData = checkNotNull(publishDepositTxRequest.offererPaymentAccountContractData);
|
||||
final PaymentAccountFilter[] appliedPaymentAccountFilter = new PaymentAccountFilter[1];
|
||||
if (processModel.isPeersPaymentAccountDataAreBanned(paymentAccountContractData, appliedPaymentAccountFilter)) {
|
||||
failed("Other trader is banned by his payment account data.\n" +
|
||||
failed("Other trader is banned by his trading account data.\n" +
|
||||
"paymentAccountContractData=" + paymentAccountContractData.getPaymentDetails() + "\n" +
|
||||
"banFilter=" + appliedPaymentAccountFilter[0].toString());
|
||||
return;
|
||||
|
|
|
@ -72,14 +72,14 @@ public class TradeStatisticsManager {
|
|||
|
||||
HashSet<TradeStatistics> persisted = statisticsStorage.initAndGetPersistedWithFileName("TradeStatistics");
|
||||
if (persisted != null)
|
||||
persisted.stream().forEach(this::add);
|
||||
persisted.stream().forEach(e -> add(e, false));
|
||||
|
||||
p2PService.addHashSetChangedListener(new HashMapChangedListener() {
|
||||
@Override
|
||||
public void onAdded(ProtectedStorageEntry data) {
|
||||
final StoragePayload storagePayload = data.getStoragePayload();
|
||||
if (storagePayload instanceof TradeStatistics)
|
||||
add((TradeStatistics) storagePayload);
|
||||
add((TradeStatistics) storagePayload, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,17 +92,19 @@ public class TradeStatisticsManager {
|
|||
p2PService.getP2PDataStorage().getMap().values().forEach(e -> {
|
||||
final StoragePayload storagePayload = e.getStoragePayload();
|
||||
if (storagePayload instanceof TradeStatistics)
|
||||
add((TradeStatistics) storagePayload);
|
||||
add((TradeStatistics) storagePayload, false);
|
||||
});
|
||||
}
|
||||
|
||||
public void add(TradeStatistics tradeStatistics) {
|
||||
public void add(TradeStatistics tradeStatistics, boolean storeLocally) {
|
||||
if (!tradeStatisticsSet.contains(tradeStatistics)) {
|
||||
boolean itemAlreadyAdded = tradeStatisticsSet.stream().filter(e -> (e.getOfferId().equals(tradeStatistics.getOfferId()))).findAny().isPresent();
|
||||
if (!itemAlreadyAdded) {
|
||||
tradeStatisticsSet.add(tradeStatistics);
|
||||
observableTradeStatisticsSet.add(tradeStatistics);
|
||||
statisticsStorage.queueUpForSave(new HashSet<>(tradeStatisticsSet), 2000);
|
||||
|
||||
if (storeLocally)
|
||||
statisticsStorage.queueUpForSave(new HashSet<>(tradeStatisticsSet), 2000);
|
||||
|
||||
dump();
|
||||
} else {
|
||||
|
|
|
@ -129,10 +129,10 @@ public final class Preferences implements Persistable {
|
|||
|
||||
private String buyScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode();
|
||||
private String sellScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode();
|
||||
private int tradeStatisticsTickUnitIndex = 0;
|
||||
private int tradeStatisticsTickUnitIndex = 3;
|
||||
|
||||
private boolean useStickyMarketPrice = false;
|
||||
private boolean sortMarketCurrenciesNumerically = false;
|
||||
private boolean sortMarketCurrenciesNumerically = true;
|
||||
private boolean usePercentageBasedPrice = false;
|
||||
private Map<String, String> peerTagMap = new HashMap<>();
|
||||
@Nullable
|
||||
|
|
160
doc/build.md
160
doc/build.md
|
@ -21,43 +21,63 @@ If `java` is not found, or your version is anything less than `1.8.0_66`, then f
|
|||
|
||||
#### 1.1 Debian based systems (Ubuntu)
|
||||
|
||||
To install OpenJDK use:
|
||||
You can use either OpenJDK or Oracle JDK.
|
||||
|
||||
**To install OpenJDK use:**
|
||||
|
||||
$ sudo apt-get install openjdk-8-jdk maven libopenjfx-java
|
||||
|
||||
To install the Oracle JDK use:
|
||||
|
||||
Unfortunately, Ubuntu 14.04 & Linux Mint 17.3 are missing OpenJdk 8 and OpenJFX, so this might be useful:
|
||||
|
||||
If `openjdk-8-jdk` is not found you can add this ppa, update, then try again:
|
||||
|
||||
$ sudo apt-add-repository ppa:openjdk-r/ppa && sudo apt-get install openjdk-8-jdk
|
||||
|
||||
If `libopenjfx-java` is not found you can build & install it yourself:
|
||||
|
||||
* [How to install OpenJFX on Ubuntu 14.04 or Linux Mint 17.3](http://askubuntu.com/questions/833193/how-do-i-install-openjfx-on-ubuntu-14-04-linux-mint-17)
|
||||
|
||||
**To install the Oracle JDK use:**
|
||||
|
||||
$ sudo add-apt-repository ppa:webupd8team/java
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get -y install oracle-java8-installer
|
||||
|
||||
Check if $JAVA_HOME is set
|
||||
|
||||
**Check if $JAVA_HOME is set:**
|
||||
|
||||
$ echo $JAVA_HOME
|
||||
|
||||
If $JAVA_HOME is not present, add it to the .bashrc file
|
||||
|
||||
$ touch .bashrc
|
||||
$ gedit .bashrc
|
||||
$ export JAVA_HOME=/usr/lib/jvm/java-8-oracle
|
||||
$ echo $JAVA_HOME
|
||||
If `$JAVA_HOME` is not present, open your `.bashrc` file:
|
||||
|
||||
$ touch ~/.bashrc
|
||||
$ gedit ~/.bashrc
|
||||
|
||||
For OpenJDK add: `export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64`
|
||||
For Oracle JDK add: `export JAVA_HOME=/usr/lib/jvm/java-8-oracle`
|
||||
Save and close the file.
|
||||
|
||||
Reload the file in your shell:
|
||||
|
||||
$ . ~/.bashrc
|
||||
$ echo $JAVA_HOME
|
||||
|
||||
#### 1.2 Other systems
|
||||
|
||||
[Download and install the latest JDK]( http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) for your platform.
|
||||
[Download and install the latest Oracle JDK]( http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) for your platform.
|
||||
|
||||
Build bitcoinj
|
||||
-----------------
|
||||
### 2. Install bitcoinj fork
|
||||
> _**NOTE:**
|
||||
Bitcoinj versions later than 0.13.1 has removed support for Java serialisation.
|
||||
In version 0.13.1 is also missing support for Java serialisation in MainNetParams (HttpDiscovery.Details).
|
||||
We removed usage of Cartographer/HttpDiscovery and fixed privacy issues with Bloom Filters at our [fork version 0.13.1.5](https://github.com/bitsquare/bitcoinj/tree/FixBloomFilters).
|
||||
Beside the Java serialisation issues there are [privacy concerns](http://bitcoin-development.narkive.com/hczWIAby/bitcoin-development-cartographer#post3) regarding Cartographer.
|
||||
### 2. Install bitcoinj fork
|
||||
> _**NOTE:**
|
||||
Bitcoinj versions later than 0.13.1 has removed support for Java serialisation.
|
||||
Version 0.13.1 is also missing support for Java serialisation in MainNetParams (HttpDiscovery.Details).
|
||||
We removed usage of Cartographer/HttpDiscovery and fixed privacy issues with Bloom Filters in our [fork of version 0.13.1.5](https://github.com/bitsquare/bitcoinj/tree/FixBloomFilters).
|
||||
Beside the Java serialisation issues there are [privacy concerns](http://bitcoin-development.narkive.com/hczWIAby/bitcoin-development-cartographer#post3) regarding Cartographer.
|
||||
Here is a Github issue with background and open tasks regarding [Bloom Filters](https://github.com/bitsquare/bitsquare/issues/414)._
|
||||
|
||||
$ git clone -b FixBloomFilters https://github.com/bitsquare/bitcoinj.git
|
||||
$ cd bitcoinj
|
||||
|
||||
$ git clone -b FixBloomFilters https://github.com/bitsquare/bitcoinj.git
|
||||
$ cd bitcoinj
|
||||
$ mvn clean install -DskipTests -Dmaven.javadoc.skip=true
|
||||
|
||||
Prepare Bitsquare build
|
||||
|
@ -65,44 +85,44 @@ Prepare Bitsquare build
|
|||
|
||||
### 3. Get Bitsquare source code and build a preliminary Bitsquare version
|
||||
|
||||
You need to get the Bitsquare dependencies first as we need to copy the BountyCastle jar to the JRE directory as well as the jdkfix jar.
|
||||
You need to get the Bitsquare dependencies first as we need to copy the BouncyCastle jar to the JRE directory as well as the jdkfix jar.
|
||||
|
||||
$ git clone https://github.com/bitsquare/bitsquare.git
|
||||
$ cd bitsquare
|
||||
$ mvn clean package -DskipTests -Dmaven.javadoc.skip=true
|
||||
|
||||
|
||||
### 4. Copy the jdkfix jar file
|
||||
|
||||
Copy the jdkfix-0.4.9.6.jar from the Bitsquare jdkfix/target directory to $JAVA_HOME/jre/lib/ext/.
|
||||
jdkfix-0.4.9.6.jar includes a bugfix of the SortedList class which will be released with the next JDK version.
|
||||
|
||||
Copy the jdkfix-0.4.9.6.jar from the Bitsquare jdkfix/target directory to $JAVA_HOME/jre/lib/ext/.
|
||||
jdkfix-0.4.9.6.jar includes a [bugfix of the SortedList class](https://github.com/jonathancross/bitsquare/blob/master/jdkfix/src/main/java/javafx/collections/transformation/SortedList.java#L2) which will be released with the next JDK version.
|
||||
We need to load that class before the default java class. This step will be removed once the bugfix is in the official JDK.
|
||||
|
||||
$ sudo cp bitsquare/jdkfix/target/jdkfix-0.4.9.6.jar $JAVA_HOME/jre/lib/ext/jdkfix-0.4.9.6.jar
|
||||
|
||||
### 5. Copy the BountyCastle provider jar file
|
||||
$ sudo cp jdkfix/target/jdkfix-0.4.9.6.jar $JAVA_HOME/jre/lib/ext/
|
||||
|
||||
Copy the BountyCastle provider jar file from the local maven repository to the jre/lib/ext directory.
|
||||
### 5. Copy the BouncyCastle provider jar file
|
||||
|
||||
Copy the BouncyCastle provider jar file from the local maven repository to the jre/lib/ext directory.
|
||||
This prevents a "JCE cannot authenticate the provider BC" exception when starting the Bitsquare client.
|
||||
|
||||
$ sudo cp ~/.m2/repository/org/bouncycastle/bcprov-jdk15on/1.53/bcprov-jdk15on-1.53.jar $JAVA_HOME/jre/lib/ext/bcprov-jdk15on-1.53.jar
|
||||
|
||||
$ sudo cp ~/.m2/repository/org/bouncycastle/bcprov-jdk15on/1.53/bcprov-jdk15on-1.53.jar $JAVA_HOME/jre/lib/ext/
|
||||
|
||||
### 6. Edit the java.security file and add BouncyCastleProvider
|
||||
|
||||
Add org.bouncycastle.jce.provider.BouncyCastleProvider as last entry at: List of providers and their preference orders
|
||||
E.g.:
|
||||
security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
|
||||
|
||||
$ sudo gedit $JAVA_HOME/jre/lib/security/java.security
|
||||
... edit and save
|
||||
|
||||
|
||||
### 7. Enable unlimited Strength for cryptographic keys (if Oracle JDK is used)
|
||||
|
||||
If you are using Oracle JDK you need to follow the following step. If you use OpenJDK + OpenJFX you can skip that step.
|
||||
Bitsquare uses 256 bit length keys which are still not permitted by default.
|
||||
Get around that ridiculous fact by adding the missing [jars from Oracle](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html).
|
||||
Please follow the steps described in the Readme file at the downloaded package.
|
||||
Bitsquare uses 256 bit length keys which are still not permitted by default.
|
||||
Get around that ridiculous fact by adding the missing [jars from Oracle](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html).
|
||||
Please follow the steps described in the Readme file in the downloaded package.
|
||||
You will get an error when building Bitsquare package if you don't have these.
|
||||
|
||||
|
||||
$ wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jce/8/jce_policy-8.zip
|
||||
$ unzip jce_policy-8.zip
|
||||
$ sudo cp UnlimitedJCEPolicyJDK8/US_export_policy.jar $JAVA_HOME/jre/lib/security/US_export_policy.jar
|
||||
|
@ -117,11 +137,11 @@ Build Bitsquare
|
|||
|
||||
### 8. Build final Bitsquare jar
|
||||
|
||||
Now we have all prepared to build the correct Bitsquare jar.
|
||||
|
||||
Now we have all prepared to build the correct Bitsquare jar.
|
||||
|
||||
$ mvn clean package -DskipTests -Dmaven.javadoc.skip=true
|
||||
|
||||
When the build completes, you will find an executable jar: `gui/target/shaded.jar`.
|
||||
|
||||
When the build completes, you will find an executable jar: `gui/target/shaded.jar`.
|
||||
To run it use:
|
||||
|
||||
$ java -jar gui/target/shaded.jar
|
||||
|
@ -129,52 +149,52 @@ To run it use:
|
|||
Build binaries
|
||||
-----------------
|
||||
|
||||
If you want to build the binaryies check out the build scripts under the package directory.
|
||||
If you want to build the binaries check out the build scripts under the package directory.
|
||||
|
||||
Development mode
|
||||
-----------------
|
||||
|
||||
|
||||
Please check out our wiki for more information about [testing](https://github.com/bitsquare/bitsquare/wiki/Testing-Bitsquare-with-Mainnet)
|
||||
and how to use [regtest](https://github.com/bitsquare/bitsquare/wiki/How-to-use-Bitsquare-with-regtest-%28advanced%29)
|
||||
|
||||
Here are example program arguments for using regtest with localhost environment (not using Tor):
|
||||
|
||||
$ java -jar seednode/target/SeedNode.jar --bitcoinNetwork=REGTEST --useLocalhost=true --myAddress=localhost:2002 --nodePort=2002 --appName=Bitsquare_seed_node_localhost_2002
|
||||
|
||||
$ java -jar gui/target/shaded.jar --bitcoinNetwork=REGTEST --useLocalhost=true --myAddress=localhost:2222 --nodePort=2222 --appName=Bitsquare-Local-Regtest-Arbitrator
|
||||
|
||||
$ java -jar gui/target/shaded.jar --bitcoinNetwork=REGTEST --useLocalhost=true --myAddress=localhost:3333 --nodePort=3333 --appName=Bitsquare-Local-Regtest-Alice
|
||||
|
||||
Here are example program arguments for using regtest with localhost environment (not using Tor):
|
||||
|
||||
$ java -jar seednode/target/SeedNode.jar --bitcoinNetwork=REGTEST --useLocalhost=true --myAddress=localhost:2002 --nodePort=2002 --appName=Bitsquare_seed_node_localhost_2002
|
||||
|
||||
$ java -jar gui/target/shaded.jar --bitcoinNetwork=REGTEST --useLocalhost=true --myAddress=localhost:2222 --nodePort=2222 --appName=Bitsquare-Local-Regtest-Arbitrator
|
||||
|
||||
$ java -jar gui/target/shaded.jar --bitcoinNetwork=REGTEST --useLocalhost=true --myAddress=localhost:3333 --nodePort=3333 --appName=Bitsquare-Local-Regtest-Alice
|
||||
|
||||
$ java -jar gui/target/shaded.jar --bitcoinNetwork=REGTEST --useLocalhost=true --myAddress=localhost:4444 --nodePort=4444 --appName=Bitsquare-Local-Regtest-Bob
|
||||
|
||||
|
||||
|
||||
|
||||
Running local seed node with Tor and RegTest
|
||||
-----------------
|
||||
|
||||
If you want to run locally a seed node via Tor you need to add your seed node's hidden service address to the SeedNodesRepository.java class.
|
||||
You can find the hidden service address after you started once a seed node. Start it with a placeholder address like:
|
||||
|
||||
You can find the hidden service address after you started once a seed node. Start it with a placeholder address like:
|
||||
|
||||
$ java -jar seednode/target/SeedNode.jar --bitcoinNetwork=REGTEST --nodePort=8002 --myAddress=xxxxxxxx.onion:8002 --appName=Bitsquare_seed_node_xxxxxxxx.onion_8000
|
||||
|
||||
Once the hidden service is published (check console output) quit the seed node and copy the hidden service address from the console output.
|
||||
|
||||
Once the hidden service is published (check console output) quit the seed node and copy the hidden service address from the console output.
|
||||
Alternatively you can navigate to the application directory and open Bitsquare_seed_node_xxxxxxx.onion_8002/tor/hiddenservice/hostname.
|
||||
use that hidden service address also to rename the xxxxxxx placeholder of your Bitsquare_seed_node_xxxxxxx.onion_8002 directory.
|
||||
Start again the SeedNode.jar now with the correct hidden service address.
|
||||
Instructions are also at the SeedNodesRepository class.
|
||||
|
||||
Here are example program arguments for using regtest and using the Tor network (example onion address is ewdkppp3vicnbgqt):
|
||||
|
||||
$ java -jar seednode/target/SeedNode.jar ewdkppp3vicnbgqt.onion:8002 2 50
|
||||
|
||||
$ java -jar seednode/target/SeedNode.jar --bitcoinNetwork=REGTEST --nodePort=8002 --myAddress=ewdkppp3vicnbgqt.onion:8002 --appName=Bitsquare_seed_node_ewdkppp3vicnbgqt.oinion_8002
|
||||
|
||||
$ java -jar gui/target/shaded.jar --bitcoinNetwork=REGTEST --myAddress=localhost:2222 --nodePort=2222 --appName=Bitsquare-Local-Regtest-Arbitrator
|
||||
|
||||
$ java -jar gui/target/shaded.jar --bitcoinNetwork=REGTEST --myAddress=localhost:3333 --nodePort=3333 --appName=Bitsquare-Local-Regtest-Alice
|
||||
|
||||
|
||||
Here are example program arguments for using regtest and using the Tor network (example onion address is ewdkppp3vicnbgqt):
|
||||
|
||||
$ java -jar seednode/target/SeedNode.jar ewdkppp3vicnbgqt.onion:8002 2 50
|
||||
|
||||
$ java -jar seednode/target/SeedNode.jar --bitcoinNetwork=REGTEST --nodePort=8002 --myAddress=ewdkppp3vicnbgqt.onion:8002 --appName=Bitsquare_seed_node_ewdkppp3vicnbgqt.oinion_8002
|
||||
|
||||
$ java -jar gui/target/shaded.jar --bitcoinNetwork=REGTEST --myAddress=localhost:2222 --nodePort=2222 --appName=Bitsquare-Local-Regtest-Arbitrator
|
||||
|
||||
$ java -jar gui/target/shaded.jar --bitcoinNetwork=REGTEST --myAddress=localhost:3333 --nodePort=3333 --appName=Bitsquare-Local-Regtest-Alice
|
||||
|
||||
$ java -jar gui/target/shaded.jar --bitcoinNetwork=REGTEST --myAddress=localhost:4444 --nodePort=4444 --appName=Bitsquare-Local-Regtest-Bob
|
||||
|
||||
|
||||
|
||||
|
||||
Problems?
|
||||
---------
|
||||
|
||||
|
|
|
@ -172,7 +172,7 @@ public class BitsquareApp extends Application {
|
|||
mainView.setPersistedFilesCorrupted(corruptedDatabaseFiles);
|
||||
});*/
|
||||
|
||||
scene = new Scene(mainView.getRoot(), 1200, 740);
|
||||
scene = new Scene(mainView.getRoot(), 1200, 700); //740
|
||||
|
||||
Font.loadFont(getClass().getResource("/fonts/Verdana.ttf").toExternalForm(), 13);
|
||||
Font.loadFont(getClass().getResource("/fonts/VerdanaBold.ttf").toExternalForm(), 13);
|
||||
|
@ -212,11 +212,11 @@ public class BitsquareApp extends Application {
|
|||
// configure the primary stage
|
||||
primaryStage.setTitle(env.getRequiredProperty(APP_NAME_KEY));
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.setMinWidth(1190);
|
||||
primaryStage.setMinWidth(1000); // 1190
|
||||
primaryStage.setMinHeight(620);
|
||||
|
||||
// on windows the title icon is also used as task bar icon in a larger size
|
||||
// on Linux no title icon is supported but also a large task bar icon is derived form that title icon
|
||||
// on Linux no title icon is supported but also a large task bar icon is derived from that title icon
|
||||
String iconPath;
|
||||
if (Utilities.isOSX())
|
||||
iconPath = ImageUtil.isRetina() ? "/images/window_icon@2x.png" : "/images/window_icon.png";
|
||||
|
@ -235,8 +235,8 @@ public class BitsquareApp extends Application {
|
|||
String osArchitecture = Utilities.getOSArchitecture();
|
||||
// We don't force a shutdown as the osArchitecture might in strange cases return a wrong value.
|
||||
// Needs at least more testing on different machines...
|
||||
new Popup<>().warning("You have probably the wrong version installed for the architecture of your computer.\n" +
|
||||
"Your computers architecture is: " + osArchitecture + ".\n" +
|
||||
new Popup<>().warning("You probably have the wrong Bitsquare version for this computer.\n" +
|
||||
"Your computer's architecture is: " + osArchitecture + ".\n" +
|
||||
"The Bitsquare binary you installed is: " + Utilities.getJVMArchitecture() + ".\n" +
|
||||
"Please shut down and re-install the correct version (" + osArchitecture + ").")
|
||||
.show();
|
||||
|
@ -358,7 +358,7 @@ public class BitsquareApp extends Application {
|
|||
if (!shutDownRequested) {
|
||||
new Popup().headLine("Shut down in progress")
|
||||
.backgroundInfo("Shutting down application can take a few seconds.\n" +
|
||||
"Please don't interrupt that process.")
|
||||
"Please don't interrupt this process.")
|
||||
.hideCloseButton()
|
||||
.useAnimation(false)
|
||||
.show();
|
||||
|
|
|
@ -59,7 +59,7 @@ bg color of non edit textFields: fafafa
|
|||
-bs-buy: -bs-yellow;
|
||||
-bs-buy-focus: derive(-bs-buy, -50%);
|
||||
-bs-buy-hover: derive(-bs-buy, -10%);
|
||||
-bs-buy-transparent: derive(-bs-buy, 95%);
|
||||
-bs-buy-transparent: derive(-bs-buy, 75%);
|
||||
|
||||
-bs-sell: -bs-turquoise;
|
||||
-bs-sell-focus: derive(-bs-sell, -50%);
|
||||
|
|
|
@ -43,7 +43,7 @@ public class AliPayForm extends PaymentMethodForm {
|
|||
private InputTextField accountNrInputTextField;
|
||||
|
||||
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account nr.:", ((AliPayAccountContractData) paymentAccountContractData).getAccountNr());
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account no.:", ((AliPayAccountContractData) paymentAccountContractData).getAccountNr());
|
||||
return gridRow;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ public class AliPayForm extends PaymentMethodForm {
|
|||
public void addFormForAddAccount() {
|
||||
gridRowFrom = gridRow + 1;
|
||||
|
||||
accountNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Account nr.:").second;
|
||||
accountNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Account no.:").second;
|
||||
accountNrInputTextField.setValidator(aliPayValidator);
|
||||
accountNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
|
||||
aliPayAccount.setAccountNr(newValue);
|
||||
|
@ -84,7 +84,7 @@ public class AliPayForm extends PaymentMethodForm {
|
|||
gridRowFrom = gridRow;
|
||||
addLabelTextField(gridPane, gridRow, "Account name:", aliPayAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(aliPayAccount.getPaymentMethod().getId()));
|
||||
TextField field = addLabelTextField(gridPane, ++gridRow, "Account nr.:", aliPayAccount.getAccountNr()).second;
|
||||
TextField field = addLabelTextField(gridPane, ++gridRow, "Account no.:", aliPayAccount.getAccountNr()).second;
|
||||
field.setMouseTransparent(false);
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", aliPayAccount.getSingleTradeCurrency().getNameAndCode());
|
||||
addAllowedPeriod();
|
||||
|
|
|
@ -44,7 +44,7 @@ public class ClearXchangeForm extends PaymentMethodForm {
|
|||
|
||||
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account holder name:", ((ClearXchangeAccountContractData) paymentAccountContractData).getHolderName());
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Email or mobile nr.:", ((ClearXchangeAccountContractData) paymentAccountContractData).getEmailOrMobileNr());
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Email or mobile no.:", ((ClearXchangeAccountContractData) paymentAccountContractData).getEmailOrMobileNr());
|
||||
return gridRow;
|
||||
}
|
||||
|
||||
|
@ -64,8 +64,8 @@ public class ClearXchangeForm extends PaymentMethodForm {
|
|||
clearXchangeAccount.setHolderName(newValue);
|
||||
updateFromInputs();
|
||||
});
|
||||
|
||||
mobileNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Email or mobile nr.:").second;
|
||||
|
||||
mobileNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Email or mobile no.:").second;
|
||||
mobileNrInputTextField.setValidator(clearXchangeValidator);
|
||||
mobileNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
|
||||
clearXchangeAccount.setEmailOrMobileNr(newValue);
|
||||
|
@ -93,7 +93,7 @@ public class ClearXchangeForm extends PaymentMethodForm {
|
|||
addLabelTextField(gridPane, gridRow, "Account name:", clearXchangeAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(clearXchangeAccount.getPaymentMethod().getId()));
|
||||
addLabelTextField(gridPane, ++gridRow, "Account holder name:", clearXchangeAccount.getHolderName());
|
||||
TextField field = addLabelTextField(gridPane, ++gridRow, "Email or mobile nr.:", clearXchangeAccount.getEmailOrMobileNr()).second;
|
||||
TextField field = addLabelTextField(gridPane, ++gridRow, "Email or mobile no.:", clearXchangeAccount.getEmailOrMobileNr()).second;
|
||||
field.setMouseTransparent(false);
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", clearXchangeAccount.getSingleTradeCurrency().getNameAndCode());
|
||||
addAllowedPeriod();
|
||||
|
|
|
@ -45,7 +45,7 @@ public class PerfectMoneyForm extends PaymentMethodForm {
|
|||
private InputTextField accountNrInputTextField;
|
||||
|
||||
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account nr.:", ((PerfectMoneyAccountContractData) paymentAccountContractData).getAccountNr());
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account no.:", ((PerfectMoneyAccountContractData) paymentAccountContractData).getAccountNr());
|
||||
return gridRow;
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ public class PerfectMoneyForm extends PaymentMethodForm {
|
|||
public void addFormForAddAccount() {
|
||||
gridRowFrom = gridRow + 1;
|
||||
|
||||
accountNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Account nr.:").second;
|
||||
accountNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Account no.:").second;
|
||||
accountNrInputTextField.setValidator(perfectMoneyValidator);
|
||||
accountNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
|
||||
perfectMoneyAccount.setAccountNr(newValue);
|
||||
|
@ -90,7 +90,7 @@ public class PerfectMoneyForm extends PaymentMethodForm {
|
|||
gridRowFrom = gridRow;
|
||||
addLabelTextField(gridPane, gridRow, "Account name:", perfectMoneyAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(perfectMoneyAccount.getPaymentMethod().getId()));
|
||||
TextField field = addLabelTextField(gridPane, ++gridRow, "Account nr.:", perfectMoneyAccount.getAccountNr()).second;
|
||||
TextField field = addLabelTextField(gridPane, ++gridRow, "Account no.:", perfectMoneyAccount.getAccountNr()).second;
|
||||
field.setMouseTransparent(false);
|
||||
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", perfectMoneyAccount.getSingleTradeCurrency().getNameAndCode());
|
||||
|
|
|
@ -45,7 +45,7 @@ public class SwishForm extends PaymentMethodForm {
|
|||
|
||||
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
|
||||
addLabelTextField(gridPane, ++gridRow, "Account holder name:", ((SwishAccountContractData) paymentAccountContractData).getHolderName());
|
||||
addLabelTextField(gridPane, ++gridRow, "Mobile nr.:", ((SwishAccountContractData) paymentAccountContractData).getMobileNr());
|
||||
addLabelTextField(gridPane, ++gridRow, "Mobile no.:", ((SwishAccountContractData) paymentAccountContractData).getMobileNr());
|
||||
return gridRow;
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ public class SwishForm extends PaymentMethodForm {
|
|||
updateFromInputs();
|
||||
});
|
||||
|
||||
mobileNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Mobile nr.:").second;
|
||||
mobileNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Mobile no.:").second;
|
||||
mobileNrInputTextField.setValidator(swishValidator);
|
||||
mobileNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
|
||||
swishAccount.setMobileNr(newValue);
|
||||
|
@ -94,7 +94,7 @@ public class SwishForm extends PaymentMethodForm {
|
|||
addLabelTextField(gridPane, gridRow, "Account name:", swishAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(swishAccount.getPaymentMethod().getId()));
|
||||
addLabelTextField(gridPane, ++gridRow, "Account holder name:", swishAccount.getHolderName());
|
||||
TextField field = addLabelTextField(gridPane, ++gridRow, "Mobile nr.:", swishAccount.getMobileNr()).second;
|
||||
TextField field = addLabelTextField(gridPane, ++gridRow, "Mobile no.:", swishAccount.getMobileNr()).second;
|
||||
field.setMouseTransparent(false);
|
||||
addLabelTextField(gridPane, ++gridRow, "Currency:", swishAccount.getSingleTradeCurrency().getNameAndCode());
|
||||
addAllowedPeriod();
|
||||
|
|
|
@ -137,11 +137,11 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
|||
Pane disputesButtonHolder = new Pane(disputesButton);
|
||||
|
||||
HBox leftNavPane = new HBox(marketButton, buyButton, sellButton, portfolioButtonHolder, fundsButton, disputesButtonHolder) {{
|
||||
setSpacing(10);
|
||||
setLeftAnchor(this, 10d);
|
||||
setTopAnchor(this, 0d);
|
||||
}};
|
||||
|
||||
|
||||
Tuple3<ComboBox<PriceFeedComboBoxItem>, Label, VBox> marketPriceBox = getMarketPriceBox("Market price");
|
||||
ComboBox<PriceFeedComboBoxItem> priceComboBox = marketPriceBox.first;
|
||||
|
||||
|
@ -176,11 +176,18 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
|||
|
||||
HBox rightNavPane = new HBox(marketPriceBox.third, availableBalanceBox.second, reservedBalanceBox.second, lockedBalanceBox.second,
|
||||
settingsButton, accountButton) {{
|
||||
setSpacing(10);
|
||||
setRightAnchor(this, 10d);
|
||||
setTopAnchor(this, 0d);
|
||||
}};
|
||||
|
||||
root.widthProperty().addListener((observable, oldValue, newValue) -> {
|
||||
double w = (double) newValue;
|
||||
if (w > 0) {
|
||||
leftNavPane.setSpacing(w >= 1080 ? 10 : 5);
|
||||
rightNavPane.setSpacing(w >= 1080 ? 10 : 5);
|
||||
}
|
||||
});
|
||||
|
||||
AnchorPane contentContainer = new AnchorPane() {{
|
||||
setId("content-pane");
|
||||
setLeftAnchor(this, 0d);
|
||||
|
@ -258,7 +265,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
|||
private Tuple2<TextField, VBox> getBalanceBox(String text) {
|
||||
TextField textField = new TextField();
|
||||
textField.setEditable(false);
|
||||
textField.setPrefWidth(140);
|
||||
textField.setPrefWidth(110); //140
|
||||
textField.setMouseTransparent(true);
|
||||
textField.setFocusTraversable(false);
|
||||
textField.setStyle("-fx-alignment: center; -fx-background-color: white;");
|
||||
|
|
|
@ -142,7 +142,7 @@ public class MainViewModel implements ViewModel {
|
|||
final BooleanProperty bootstrapComplete = new SimpleBooleanProperty();
|
||||
|
||||
// software update
|
||||
final String version = "v." + Version.VERSION;
|
||||
final String version = "v" + Version.VERSION;
|
||||
|
||||
final BooleanProperty showAppScreen = new SimpleBooleanProperty();
|
||||
final StringProperty numPendingTradesAsString = new SimpleStringProperty();
|
||||
|
@ -193,7 +193,7 @@ public class MainViewModel implements ViewModel {
|
|||
this.preferences = preferences;
|
||||
this.alertManager = alertManager;
|
||||
this.privateNotificationManager = privateNotificationManager;
|
||||
this.filterManager = filterManager; // Needed to be referenced so we get it initialized and get the eventlistener registered
|
||||
this.filterManager = filterManager; // Reference so it's initialized and eventlistener gets registered
|
||||
this.walletPasswordWindow = walletPasswordWindow;
|
||||
this.notificationCenter = notificationCenter;
|
||||
this.tacWindow = tacWindow;
|
||||
|
@ -298,11 +298,11 @@ public class MainViewModel implements ViewModel {
|
|||
result = warning;
|
||||
} else {
|
||||
if (dataReceived && hiddenService)
|
||||
result = "Nr. of P2P network peers: " + numPeers;
|
||||
result = "P2P network peers: " + numPeers;
|
||||
else if (peers == 0)
|
||||
result = state;
|
||||
else
|
||||
result = state + " / Nr. of P2P network peers: " + numPeers;
|
||||
result = state + " / P2P network peers: " + numPeers;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
@ -444,7 +444,7 @@ public class MainViewModel implements ViewModel {
|
|||
if (exception == null) {
|
||||
double percentage = (double) downloadPercentage;
|
||||
int peers = (int) numPeers;
|
||||
String numPeersString = "Nr. of Bitcoin network peers: " + peers;
|
||||
String numPeersString = "Bitcoin network peers: " + peers;
|
||||
|
||||
btcSyncProgress.set(percentage);
|
||||
if (percentage == 1) {
|
||||
|
@ -456,14 +456,14 @@ public class MainViewModel implements ViewModel {
|
|||
result = numPeersString + " / connecting to " + btcNetworkAsString;
|
||||
}
|
||||
} else {
|
||||
result = "Nr. of Bitcoin network peers: " + numBtcPeers + " / connecting to " + btcNetworkAsString + " failed";
|
||||
result = "Bitcoin network peers: " + numBtcPeers + " / connecting to " + btcNetworkAsString + " failed";
|
||||
if (exception instanceof TimeoutException) {
|
||||
walletServiceErrorMsg.set("Connecting to the bitcoin network failed because of a timeout.");
|
||||
} else if (exception.getCause() instanceof BlockStoreException) {
|
||||
log.error(exception.getMessage());
|
||||
// Ugly, but no other way to cover that specific case
|
||||
if (exception.getMessage().equals("Store file is already locked by another process"))
|
||||
new Popup().warning("Bitsquare is already running. You cannot run 2 instances of Bitsquare.")
|
||||
new Popup().warning("Bitsquare is already running. You cannot run two instances of Bitsquare.")
|
||||
.closeButtonText("Shut down")
|
||||
.onClose(BitsquareApp.shutDownHandler::run)
|
||||
.show();
|
||||
|
@ -616,7 +616,7 @@ public class MainViewModel implements ViewModel {
|
|||
|
||||
String remindPasswordAndBackupKey = "remindPasswordAndBackup";
|
||||
user.getPaymentAccountsAsObservable().addListener((SetChangeListener<PaymentAccount>) change -> {
|
||||
if (preferences.showAgain(remindPasswordAndBackupKey) && change.wasAdded()) {
|
||||
if (!walletService.getWallet().isEncrypted() && preferences.showAgain(remindPasswordAndBackupKey) && change.wasAdded()) {
|
||||
new Popup<>().headLine("Important security recommendation")
|
||||
.information("We would like to remind you to consider using password protection for your wallet if you have not already enabled that.\n\n" +
|
||||
"It is also highly recommended to write down the wallet seed words. Those seed words are like a master password for recovering your Bitcoin wallet.\n" +
|
||||
|
|
|
@ -121,7 +121,7 @@ public class AccountView extends ActivatableView<TabPane, AccountViewModel> {
|
|||
|
||||
String key = "accountPrivacyInfo";
|
||||
if (!DevFlags.DEV_MODE)
|
||||
new Popup().backgroundInfo("In the account screen you can setup your payment accounts for national currencies " +
|
||||
new Popup().backgroundInfo("In the account screen you can setup your trading accounts for national currencies " +
|
||||
"as well as for altcoins.\n\n" +
|
||||
"For Bitcoin you don't need to set up an account.\n" +
|
||||
"You can manage your Bitsquare wallet at the \"Funds\" section.\n\n" +
|
||||
|
|
|
@ -102,9 +102,10 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
|
|||
restoreButton = addButtonAfterGroup(root, ++gridRow, "Restore wallet");
|
||||
|
||||
addTitledGroupBg(root, ++gridRow, 1, "Information", Layout.GROUP_DISTANCE);
|
||||
addMultilineLabel(root, gridRow, "Please write down you wallet seed words.\n" +
|
||||
addMultilineLabel(root, gridRow, "Please write down you wallet seed words. " +
|
||||
"You can recover your wallet with those seed words.\n\n" +
|
||||
"If you are restoring your wallet you need to use the wallet date of the wallet into which you want to restore.\n" +
|
||||
"If you are restoring your wallet you need to use the wallet date " +
|
||||
"of the wallet into which you want to restore. " +
|
||||
"So in case you restore to a new wallet it is the today's date.",
|
||||
Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
|
||||
|
|
|
@ -97,10 +97,10 @@ public class DisputesView extends ActivatableViewAndModel<TabPane, Activatable>
|
|||
.findAny().isPresent();
|
||||
|
||||
if (arbitratorsDisputesTab == null && isArbitrator) {
|
||||
arbitratorsDisputesTab = new Tab("Arbitrators support tickets");
|
||||
arbitratorsDisputesTab = new Tab("Arbitrator's support tickets");
|
||||
arbitratorsDisputesTab.setClosable(false);
|
||||
root.getTabs().add(arbitratorsDisputesTab);
|
||||
tradersDisputesTab.setText("Traders support tickets");
|
||||
tradersDisputesTab.setText("Trader's support tickets");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
});
|
||||
disputeGroups.sort((o1, o2) -> !o1.isEmpty() && !o2.isEmpty() ? o1.get(0).getOpeningDate().compareTo(o2.get(0).getOpeningDate()) : 0);
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.append("Summary of all disputes (Nr. of disputes: " + disputeGroups.size() + ")\n\n");
|
||||
stringBuilder.append("Summary of all disputes (No. of disputes: " + disputeGroups.size() + ")\n\n");
|
||||
disputeGroups.stream().forEach(disputeGroup -> {
|
||||
Dispute dispute0 = disputeGroup.get(0);
|
||||
stringBuilder.append("##########################################################################################/\n")
|
||||
|
@ -243,12 +243,12 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
disputeGroup.stream().forEach(dispute -> {
|
||||
stringBuilder
|
||||
.append("*******************************************************************************************\n")
|
||||
.append("** Traders ID: ")
|
||||
.append("** Trader's ID: ")
|
||||
.append(dispute.getTraderId())
|
||||
.append("\n*******************************************************************************************\n")
|
||||
.append("\n");
|
||||
dispute.getDisputeCommunicationMessagesAsObservableList().stream().forEach(m -> {
|
||||
String role = m.isSenderIsTrader() ? ">> Traders msg: " : "<< Arbitrators msg: ";
|
||||
String role = m.isSenderIsTrader() ? ">> Trader's msg: " : "<< Arbitrator's msg: ";
|
||||
stringBuilder.append(role)
|
||||
.append(m.getMessage())
|
||||
.append("\n");
|
||||
|
@ -264,6 +264,13 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
.actionButtonText("Copy")
|
||||
.onAction(() -> Utilities.copyToClipboard(message))
|
||||
.show();
|
||||
} else if (new KeyCodeCombination(KeyCode.U, KeyCombination.SHORTCUT_DOWN).match(event)) {
|
||||
// Hidden shortcut to re-open a dispute. Allow it also for traders not only arbitrator.
|
||||
if (selectedDispute != null) {
|
||||
if (selectedDisputeClosedPropertyListener != null)
|
||||
selectedDispute.isClosedProperty().removeListener(selectedDisputeClosedPropertyListener);
|
||||
selectedDispute.setIsClosed(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -766,7 +773,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
private void showMailboxIcon() {
|
||||
statusIcon.setVisible(true);
|
||||
AwesomeDude.setIcon(statusIcon, AwesomeIcon.ENVELOPE_ALT, "14");
|
||||
Tooltip.install(statusIcon, new Tooltip("Message saved in receivers mailbox"));
|
||||
Tooltip.install(statusIcon, new Tooltip("Message saved in receiver's mailbox"));
|
||||
statusIcon.setTextFill(Paint.valueOf("#0f87c3"));
|
||||
}
|
||||
|
||||
|
@ -1110,9 +1117,10 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
setText(isClosed ? "Closed" : "Open");
|
||||
getTableRow().setOpacity(isClosed ? 0.4 : 1);
|
||||
} else {
|
||||
if (closedProperty != null)
|
||||
if (closedProperty != null) {
|
||||
closedProperty.removeListener(listener);
|
||||
|
||||
closedProperty = null;
|
||||
}
|
||||
setText("");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
|||
walletService.getOrCreateAddressEntry(AddressEntry.Context.AVAILABLE);
|
||||
|
||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
tableView.setPlaceholder(new Label("No deposit addresses are generated yet"));
|
||||
tableView.setPlaceholder(new Label("No deposit addresses have been generated yet"));
|
||||
tableViewSelectionListener = (observableValue, oldValue, newValue) -> {
|
||||
if (newValue != null)
|
||||
fillForm(newValue.getAddressString());
|
||||
|
@ -137,7 +137,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
|||
|
||||
titledGroupBg = addTitledGroupBg(gridPane, gridRow, 3, "Fund your wallet");
|
||||
|
||||
qrCodeLabel = addLabel(gridPane, gridRow, "QR-Code:", 0);
|
||||
qrCodeLabel = addLabel(gridPane, gridRow, "", 0);
|
||||
//GridPane.setMargin(qrCodeLabel, new Insets(Layout.FIRST_ROW_DISTANCE - 9, 0, 0, 5));
|
||||
|
||||
qrCodeImageView = new ImageView();
|
||||
|
|
|
@ -246,7 +246,7 @@ public class LockedView extends ActivatableView<VBox, Void> {
|
|||
field.setTooltip(new Tooltip("Open popup for details"));
|
||||
setGraphic(field);
|
||||
} else if (item.getAddressEntry().getContext() == AddressEntry.Context.ARBITRATOR) {
|
||||
setGraphic(new Label("Arbitrators fee"));
|
||||
setGraphic(new Label("Arbitrator's fee"));
|
||||
} else {
|
||||
setGraphic(new Label("No details available"));
|
||||
}
|
||||
|
|
|
@ -246,7 +246,7 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
|||
field.setTooltip(new Tooltip("Open popup for details"));
|
||||
setGraphic(field);
|
||||
} else if (item.getAddressEntry().getContext() == AddressEntry.Context.ARBITRATOR) {
|
||||
setGraphic(new Label("Arbitrators fee"));
|
||||
setGraphic(new Label("Arbitrator's fee"));
|
||||
} else {
|
||||
setGraphic(new Label("No details available"));
|
||||
}
|
||||
|
|
|
@ -616,7 +616,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
map.entrySet().stream().forEach(e -> {
|
||||
stringBuilder.append("Nr. of transactions for amount ").
|
||||
stringBuilder.append("No. of transactions for amount ").
|
||||
append(formatter.formatCoinWithCode(Coin.valueOf(e.getKey()))).
|
||||
append(": ").
|
||||
append(e.getValue().size()).
|
||||
|
@ -649,7 +649,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
append(tuple4.forth.second).
|
||||
append(")");
|
||||
});
|
||||
String message = stringBuilder.toString() + "\nNr. of transactions by day:" + transactionsByDayStringBuilder.toString();
|
||||
String message = stringBuilder.toString() + "\nNo. of transactions by day:" + transactionsByDayStringBuilder.toString();
|
||||
new Popup().headLine("Statistical info")
|
||||
.information(message)
|
||||
.actionButtonText("Copy")
|
||||
|
|
|
@ -47,6 +47,7 @@ import javafx.scene.chart.XYChart;
|
|||
import javafx.scene.control.*;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.util.Callback;
|
||||
import javafx.util.StringConverter;
|
||||
|
@ -111,7 +112,7 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
|
|||
Label currencyLabel = new Label("Currency:");
|
||||
HBox currencyHBox = new HBox();
|
||||
currencyHBox.setSpacing(5);
|
||||
currencyHBox.setPadding(new Insets(10, -20, -10, 20));
|
||||
currencyHBox.setPadding(new Insets(5, -20, -5, 20));
|
||||
currencyHBox.setAlignment(Pos.CENTER_LEFT);
|
||||
currencyHBox.getChildren().addAll(currencyLabel, currencyComboBox);
|
||||
|
||||
|
@ -129,8 +130,10 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
|
|||
sellOfferHeaderLabel = tupleSell.forth;
|
||||
|
||||
bottomHBox = new HBox();
|
||||
bottomHBox.setSpacing(30);
|
||||
bottomHBox.setSpacing(20); //30
|
||||
bottomHBox.setAlignment(Pos.CENTER);
|
||||
HBox.setHgrow(tupleBuy.second, Priority.ALWAYS);
|
||||
HBox.setHgrow(tupleSell.second, Priority.ALWAYS);
|
||||
tupleBuy.second.setUserData("BUY");
|
||||
tupleSell.second.setUserData("SELL");
|
||||
bottomHBox.getChildren().addAll(tupleBuy.second, tupleSell.second);
|
||||
|
@ -283,13 +286,13 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
|
|||
private Tuple4<TableView<OfferListItem>, VBox, Button, Label> getOfferTable(Offer.Direction direction) {
|
||||
TableView<OfferListItem> tableView = new TableView<>();
|
||||
tableView.setMinHeight(109);
|
||||
tableView.setMinWidth(530);
|
||||
tableView.setMinWidth(480); //530
|
||||
|
||||
// price
|
||||
TableColumn<OfferListItem, OfferListItem> priceColumn = new TableColumn<>();
|
||||
priceColumn.textProperty().bind(priceColumnLabel);
|
||||
priceColumn.setMinWidth(130);
|
||||
priceColumn.setMaxWidth(130);
|
||||
priceColumn.setMinWidth(115); //130
|
||||
priceColumn.setMaxWidth(115); //130
|
||||
priceColumn.setSortable(false);
|
||||
priceColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
priceColumn.setCellFactory(
|
||||
|
@ -332,8 +335,7 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
|
|||
|
||||
// volume
|
||||
TableColumn<OfferListItem, OfferListItem> volumeColumn = new TableColumn<>();
|
||||
volumeColumn.setMinWidth(125);
|
||||
volumeColumn.setMaxWidth(125);
|
||||
volumeColumn.setMinWidth(115); //125
|
||||
volumeColumn.setSortable(false);
|
||||
volumeColumn.textProperty().bind(volumeColumnLabel);
|
||||
volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
|
@ -378,8 +380,7 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
|
|||
|
||||
// amount
|
||||
TableColumn<OfferListItem, OfferListItem> amountColumn = new TableColumn<>("Amount in BTC");
|
||||
amountColumn.setMinWidth(125);
|
||||
amountColumn.setMaxWidth(125);
|
||||
amountColumn.setMinWidth(115); //125
|
||||
amountColumn.setSortable(false);
|
||||
amountColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
amountColumn.setCellFactory(
|
||||
|
@ -401,7 +402,7 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
|
|||
|
||||
// accumulated
|
||||
TableColumn<OfferListItem, OfferListItem> accumulatedColumn = new TableColumn<>("Sum in BTC");
|
||||
accumulatedColumn.setMinWidth(130);
|
||||
accumulatedColumn.setMinWidth(100);//130
|
||||
accumulatedColumn.setSortable(false);
|
||||
accumulatedColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
accumulatedColumn.setCellFactory(
|
||||
|
|
|
@ -269,7 +269,7 @@ class OfferBookChartViewModel extends ActivatableViewModel {
|
|||
buildChartAndTableEntries(allSellOffers, Offer.Direction.SELL, sellData, topSellOfferList);
|
||||
}
|
||||
|
||||
// If there are more then 3 offers we ignore the offers which are further thn 30% from the best price
|
||||
// If there are more then 3 offers we ignore the offers which are further than 30% from the best price
|
||||
private List<Offer> filterOffersWithRelevantPrices(List<Offer> offers) {
|
||||
if (offers.size() > 3) {
|
||||
Fiat bestPrice = offers.get(0).getPrice();
|
||||
|
|
|
@ -117,9 +117,9 @@ public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewMode
|
|||
|
||||
private void updateHeaders() {
|
||||
numberOfOffersColumn.setText("All offers (" + sortedList.stream().mapToInt(item -> item.numberOfOffers).sum() + ")");
|
||||
numberOfBuyOffersColumn.setText("Buy BTC offers (" + sortedList.stream().mapToInt(item -> item.numberOfBuyOffers).sum() + ")");
|
||||
numberOfSellOffersColumn.setText("Sell BTC offers (" + sortedList.stream().mapToInt(item -> item.numberOfSellOffers).sum() + ")");
|
||||
totalAmountColumn.setText("Total amount in BTC (" + formatter.formatCoin(Coin.valueOf(sortedList.stream().mapToLong(item -> item.totalAmount.value).sum())) + ")");
|
||||
numberOfBuyOffersColumn.setText("Buy BTC (" + sortedList.stream().mapToInt(item -> item.numberOfBuyOffers).sum() + ")");
|
||||
numberOfSellOffersColumn.setText("Sell BTC (" + sortedList.stream().mapToInt(item -> item.numberOfSellOffers).sum() + ")");
|
||||
totalAmountColumn.setText("Total BTC (" + formatter.formatCoin(Coin.valueOf(sortedList.stream().mapToLong(item -> item.totalAmount.value).sum())) + ")");
|
||||
}
|
||||
|
||||
|
||||
|
@ -130,7 +130,7 @@ public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewMode
|
|||
private TableColumn<SpreadItem, SpreadItem> getCurrencyColumn() {
|
||||
TableColumn<SpreadItem, SpreadItem> column = new TableColumn<SpreadItem, SpreadItem>("Currency") {
|
||||
{
|
||||
setMinWidth(110);
|
||||
setMinWidth(160); //110
|
||||
}
|
||||
};
|
||||
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
|
@ -242,7 +242,7 @@ public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewMode
|
|||
private TableColumn<SpreadItem, SpreadItem> getTotalAmountColumn() {
|
||||
TableColumn<SpreadItem, SpreadItem> column = new TableColumn<SpreadItem, SpreadItem>("Total amount") {
|
||||
{
|
||||
setMinWidth(170);
|
||||
setMinWidth(140); //170
|
||||
}
|
||||
};
|
||||
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
|
@ -270,7 +270,7 @@ public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewMode
|
|||
private TableColumn<SpreadItem, SpreadItem> getSpreadColumn() {
|
||||
TableColumn<SpreadItem, SpreadItem> column = new TableColumn<SpreadItem, SpreadItem>("Spread") {
|
||||
{
|
||||
setMinWidth(130);
|
||||
setMinWidth(110); //130
|
||||
}
|
||||
};
|
||||
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
|
|
|
@ -130,7 +130,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
|
|||
volumeAxisYWidth = (double) newValue;
|
||||
layoutChart();
|
||||
};
|
||||
tradeStatisticsByCurrencyListener = c -> nrOfTradeStatisticsLabel.setText("Nr. of trades: " + model.tradeStatisticsByCurrency.size());
|
||||
tradeStatisticsByCurrencyListener = c -> nrOfTradeStatisticsLabel.setText("Trades: " + model.tradeStatisticsByCurrency.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -204,7 +204,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
|
|||
priceAxisX.setTickLabelFormatter(getTimeAxisStringConverter());
|
||||
volumeAxisX.setTickLabelFormatter(getTimeAxisStringConverter());
|
||||
|
||||
nrOfTradeStatisticsLabel.setText("Nr. of trades: " + model.tradeStatisticsByCurrency.size());
|
||||
nrOfTradeStatisticsLabel.setText("Trades: " + model.tradeStatisticsByCurrency.size());
|
||||
|
||||
UserThread.runAfter(this::updateChartData, 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
|
|||
return null;
|
||||
}
|
||||
});
|
||||
priceChart.setMinHeight(250);
|
||||
priceChart.setMinHeight(200);
|
||||
priceChart.setMaxHeight(300);
|
||||
priceChart.setLegendVisible(false);
|
||||
priceChart.setData(FXCollections.observableArrayList(priceSeries));
|
||||
|
@ -391,18 +391,18 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
|
|||
label.setPadding(new Insets(0, 4, 0, 0));
|
||||
|
||||
toggleGroup = new ToggleGroup();
|
||||
ToggleButton year = getToggleButton("Year", TradesChartsViewModel.TickUnit.YEAR, toggleGroup, "toggle-left");
|
||||
ToggleButton month = getToggleButton("Month", TradesChartsViewModel.TickUnit.MONTH, toggleGroup, "toggle-left");
|
||||
ToggleButton week = getToggleButton("Week", TradesChartsViewModel.TickUnit.WEEK, toggleGroup, "toggle-center");
|
||||
ToggleButton day = getToggleButton("Day", TradesChartsViewModel.TickUnit.DAY, toggleGroup, "toggle-center");
|
||||
ToggleButton hour = getToggleButton("Hour", TradesChartsViewModel.TickUnit.HOUR, toggleGroup, "toggle-center");
|
||||
ToggleButton minute10 = getToggleButton("10 Minutes", TradesChartsViewModel.TickUnit.MINUTE_10, toggleGroup, "toggle-center");
|
||||
ToggleButton minute = getToggleButton("Minute", TradesChartsViewModel.TickUnit.MINUTE, toggleGroup, "toggle-right");
|
||||
|
||||
HBox hBox = new HBox();
|
||||
hBox.setSpacing(0);
|
||||
hBox.setPadding(new Insets(5, 9, -10, 10));
|
||||
hBox.setAlignment(Pos.CENTER_LEFT);
|
||||
hBox.getChildren().addAll(currencyLabel, currencyComboBox, spacer, label, month, week, day, hour, minute10, minute);
|
||||
hBox.getChildren().addAll(currencyLabel, currencyComboBox, spacer, label, year, month, week, day, hour, minute10);
|
||||
return hBox;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,12 +61,15 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public enum TickUnit {
|
||||
YEAR,
|
||||
MONTH,
|
||||
WEEK,
|
||||
DAY,
|
||||
HOUR,
|
||||
MINUTE_10,
|
||||
MINUTE
|
||||
// TODO Can be removed after version 4.9.7
|
||||
// Not used anymore but leave it as it might be used in preferences and could cause an exception if not there.
|
||||
MINUTE
|
||||
}
|
||||
|
||||
private final TradeStatisticsManager tradeStatisticsManager;
|
||||
|
@ -325,6 +328,8 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||
|
||||
long getTickFromTime(long tradeDateAsTime, TickUnit tickUnit) {
|
||||
switch (tickUnit) {
|
||||
case YEAR:
|
||||
return TimeUnit.MILLISECONDS.toDays(tradeDateAsTime) / 365;
|
||||
case MONTH:
|
||||
return TimeUnit.MILLISECONDS.toDays(tradeDateAsTime) / 31;
|
||||
case WEEK:
|
||||
|
@ -344,6 +349,8 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||
|
||||
long getTimeFromTick(long tick, TickUnit tickUnit) {
|
||||
switch (tickUnit) {
|
||||
case YEAR:
|
||||
return TimeUnit.DAYS.toMillis(tick) * 365;
|
||||
case MONTH:
|
||||
return TimeUnit.DAYS.toMillis(tick) * 31;
|
||||
case WEEK:
|
||||
|
|
|
@ -55,7 +55,7 @@ public class VolumeBar extends Group {
|
|||
public void update(double height, double candleWidth, CandleData candleData) {
|
||||
bar.resizeRelocate(-candleWidth / 2, 0, candleWidth, height);
|
||||
tooltip.setText("Volume: " + volumeStringConverter.toString(candleData.accumulatedAmount) + "\n" +
|
||||
"Nr. of trades: " + candleData.numTrades + "\n" +
|
||||
"No. of trades: " + candleData.numTrades + "\n" +
|
||||
"Date: " + candleData.date);
|
||||
}
|
||||
|
||||
|
|
|
@ -241,14 +241,14 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
public void initWithData(Offer.Direction direction, TradeCurrency tradeCurrency) {
|
||||
boolean result = model.initWithData(direction, tradeCurrency);
|
||||
|
||||
if (!result)
|
||||
new Popup().warning("You don't have a payment account set up.").onClose(this::close).show();
|
||||
if (!result)
|
||||
new Popup().warning("You don't have a trading account set up.").onClose(this::close).show();
|
||||
|
||||
if (direction == Offer.Direction.BUY) {
|
||||
imageView.setId("image-buy-large");
|
||||
|
||||
placeOfferButton.setId("buy-button-big");
|
||||
placeOfferButton.setText("Review offer for buying bitcoin");
|
||||
placeOfferButton.setText("Review offer to buy bitcoin");
|
||||
nextButton.setId("buy-button");
|
||||
} else {
|
||||
imageView.setId("image-sell-large");
|
||||
|
@ -256,7 +256,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
totalToPayTextField.setPromptText(BSResources.get("createOffer.fundsBox.totalsNeeded.prompt"));
|
||||
|
||||
placeOfferButton.setId("sell-button-big");
|
||||
placeOfferButton.setText("Review offer for selling bitcoin");
|
||||
placeOfferButton.setText("Review offer to sell bitcoin");
|
||||
nextButton.setId("sell-button");
|
||||
}
|
||||
}
|
||||
|
@ -348,14 +348,11 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
"- Trading fee: " + model.getOfferFee() + "\n" +
|
||||
"- Bitcoin mining fee: " + model.getNetworkFee() + "\n\n" +
|
||||
|
||||
"For funding you can choose between 2 options:\n" +
|
||||
"- Transfer fund from your Bitsquare wallet OR\n" +
|
||||
"- Transfer fund from any external wallet\n\n" +
|
||||
"You can choose between two options when funding your trade:\n" +
|
||||
"- Use your Bitsquare wallet (convenient, but transactions may be linkable) OR\n" +
|
||||
"- Transfer from an external wallet (potentially more private)\n\n" +
|
||||
|
||||
"If you prefer a higher level of privacy you should use for each trade a distinct funding transaction using the external wallet option.\n" +
|
||||
"If you prefer convenience using the Bitsquare wallet for several trades might be your preferred option.\n\n" +
|
||||
|
||||
"You can see all the details for funding when you close that popup.")
|
||||
"You will see all funding options and details after closing this popup.")
|
||||
.dontShowAgainId(key, preferences)
|
||||
.show();
|
||||
}
|
||||
|
@ -483,7 +480,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
placeOfferButton.disableProperty().bind(model.isPlaceOfferButtonDisabled);
|
||||
cancelButton2.disableProperty().bind(model.cancelButtonDisabled);
|
||||
|
||||
// payment account
|
||||
// trading account
|
||||
currencyComboBox.prefWidthProperty().bind(paymentAccountsComboBox.widthProperty());
|
||||
currencyComboBox.managedProperty().bind(currencyComboBox.visibleProperty());
|
||||
currencyComboBoxLabel.visibleProperty().bind(currencyComboBox.visibleProperty());
|
||||
|
@ -531,7 +528,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
placeOfferButton.disableProperty().unbind();
|
||||
cancelButton2.disableProperty().unbind();
|
||||
|
||||
// payment account
|
||||
// trading account
|
||||
currencyComboBox.managedProperty().unbind();
|
||||
currencyComboBox.prefWidthProperty().unbind();
|
||||
currencyComboBoxLabel.visibleProperty().unbind();
|
||||
|
@ -627,7 +624,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
if (DevFlags.DEV_MODE) {
|
||||
close();
|
||||
} else if (newValue) {
|
||||
// We need a bit of delay to avoid issues with fade out/fade in of 2 popups
|
||||
// We need a bit of delay to avoid issues with fade out/fade in of 2 popups
|
||||
String key = "createOfferSuccessInfo";
|
||||
if (preferences.showAgain(key)) {
|
||||
UserThread.runAfter(() -> new Popup().headLine(BSResources.get("createOffer.success.headline"))
|
||||
|
@ -729,11 +726,11 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
}
|
||||
|
||||
private void addPaymentGroup() {
|
||||
TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, gridRow, 2, "Select payment account");
|
||||
TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, gridRow, 2, "Select trading account");
|
||||
GridPane.setColumnSpan(titledGroupBg, 3);
|
||||
|
||||
paymentAccountsComboBox = addLabelComboBox(gridPane, gridRow, "Payment account:", Layout.FIRST_ROW_DISTANCE).second;
|
||||
paymentAccountsComboBox.setPromptText("Select payment account");
|
||||
paymentAccountsComboBox = addLabelComboBox(gridPane, gridRow, "Trading account:", Layout.FIRST_ROW_DISTANCE).second;
|
||||
paymentAccountsComboBox.setPromptText("Select trading account");
|
||||
paymentAccountsComboBox.setMinWidth(300);
|
||||
editOfferElements.add(paymentAccountsComboBox);
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
|||
// If we would change the price representation in the domain we would not be backward compatible
|
||||
final StringProperty price = new SimpleStringProperty();
|
||||
|
||||
// Positive % value means always a better price form the offerers perspective:
|
||||
// Positive % value means always a better price form the offerer's perspective:
|
||||
// Buyer (with fiat): lower price as market
|
||||
// Buyer (with altcoin): higher (display) price as market (display price is inverted)
|
||||
final StringProperty marketPriceMargin = new SimpleStringProperty();
|
||||
|
@ -160,7 +160,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
|||
UserThread.runAfter(() -> {
|
||||
amount.set("1");
|
||||
minAmount.set(amount.get());
|
||||
price.set("500");
|
||||
price.set("600");
|
||||
|
||||
setAmountToModel();
|
||||
setMinAmountToModel();
|
||||
|
@ -510,7 +510,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
|||
formatter.formatCoinWithCode(dataModel.totalAvailableBalance) + " in your Bitsquare wallet.\n\n" +
|
||||
"Please fund that trade from an external Bitcoin wallet or fund your Bitsquare " +
|
||||
"wallet at \"Funds/Depost funds\".")
|
||||
.actionButtonText("Go to \"Funds/Depost funds\"")
|
||||
.actionButtonText("Go to \"Funds/Deposit funds\"")
|
||||
.onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, DepositView.class))
|
||||
.show();
|
||||
return false;
|
||||
|
@ -623,7 +623,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
|||
|
||||
public boolean isPriceInRange() {
|
||||
if (marketPriceMargin.get() != null && !marketPriceMargin.get().isEmpty()) {
|
||||
if (formatter.parsePercentStringToDouble(marketPriceMargin.get()) > preferences.getMaxPriceDistanceInPercent()) {
|
||||
if (Math.abs(formatter.parsePercentStringToDouble(marketPriceMargin.get())) > preferences.getMaxPriceDistanceInPercent()) {
|
||||
displayPriceOutOfRangePopup();
|
||||
return false;
|
||||
} else {
|
||||
|
|
|
@ -59,7 +59,7 @@ public class OfferBook {
|
|||
if (!offerBookListItems.contains(offerBookListItem)) {
|
||||
offerBookListItems.add(offerBookListItem);
|
||||
|
||||
Log.logIfStressTests("Offer added: Nr. of offers = " + offerBookListItems.size());
|
||||
Log.logIfStressTests("Offer added: No. of offers = " + offerBookListItems.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ public class OfferBook {
|
|||
OfferBookListItem item = candidate.get();
|
||||
if (offerBookListItems.contains(item)) {
|
||||
offerBookListItems.remove(item);
|
||||
Log.logIfStressTests("Offer removed: Nr. of offers = " + offerBookListItems.size());
|
||||
Log.logIfStressTests("Offer removed: No. of offers = " + offerBookListItems.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ public class OfferBook {
|
|||
.map(OfferBookListItem::new)
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
Log.logIfStressTests("Offer filled: Nr. of offers = " + offerBookListItems.size());
|
||||
Log.logIfStressTests("Offer filled: No. of offers = " + offerBookListItems.size());
|
||||
|
||||
log.debug("offerBookListItems " + offerBookListItems.size());
|
||||
} catch (Throwable t) {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
package io.bitsquare.gui.main.offer.offerbook;
|
||||
|
||||
import io.bitsquare.alert.PrivateNotificationManager;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.gui.Navigation;
|
||||
import io.bitsquare.gui.common.view.ActivatableViewAndModel;
|
||||
import io.bitsquare.gui.common.view.FxmlView;
|
||||
|
@ -36,7 +36,6 @@ import io.bitsquare.gui.main.offer.OfferView;
|
|||
import io.bitsquare.gui.main.overlays.popups.Popup;
|
||||
import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.gui.util.CurrencyListItem;
|
||||
import io.bitsquare.gui.util.GUIUtil;
|
||||
import io.bitsquare.gui.util.Layout;
|
||||
import io.bitsquare.locale.BSResources;
|
||||
|
@ -65,7 +64,6 @@ import org.fxmisc.easybind.Subscription;
|
|||
import org.fxmisc.easybind.monadic.MonadicBinding;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Optional;
|
||||
|
||||
import static io.bitsquare.gui.util.FormBuilder.*;
|
||||
|
||||
|
@ -77,7 +75,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
private BSFormatter formatter;
|
||||
private PrivateNotificationManager privateNotificationManager;
|
||||
|
||||
private ComboBox<CurrencyListItem> currencyComboBox;
|
||||
private ComboBox<TradeCurrency> currencyComboBox;
|
||||
private ComboBox<PaymentMethod> paymentMethodComboBox;
|
||||
private Button createOfferButton;
|
||||
private TableColumn<OfferBookListItem, OfferBookListItem> amountColumn, volumeColumn, marketColumn, priceColumn, paymentMethodColumn, avatarColumn;
|
||||
|
@ -90,7 +88,6 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
private ListChangeListener<OfferBookListItem> offerListListener;
|
||||
private MonadicBinding<Void> currencySelectionBinding;
|
||||
private Subscription currencySelectionSubscriber;
|
||||
private ListChangeListener<CurrencyListItem> currencyListItemsListener;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -115,7 +112,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
|
||||
currencyComboBox = addLabelComboBox(root, gridRow, "Filter by currency:", Layout.FIRST_ROW_DISTANCE).second;
|
||||
currencyComboBox.setPromptText("Select currency");
|
||||
currencyComboBox.setConverter(GUIUtil.getCurrencyListItemConverter("offers", model.preferences));
|
||||
currencyComboBox.setConverter(GUIUtil.getTradeCurrencyConverter());
|
||||
|
||||
paymentMethodComboBox = addLabelComboBox(root, ++gridRow, "Filter by payment method:").second;
|
||||
paymentMethodComboBox.setPromptText("Select payment method");
|
||||
|
@ -199,25 +196,19 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
GridPane.setHalignment(createOfferButton, HPos.RIGHT);
|
||||
GridPane.setVgrow(createOfferButton, Priority.NEVER);
|
||||
GridPane.setValignment(createOfferButton, VPos.TOP);
|
||||
offerListListener = c -> nrOfOffersLabel.setText("Nr. of offers: " + model.getOfferList().size());
|
||||
currencyListItemsListener = c -> applyCurrencyComboBoxSelection();
|
||||
offerListListener = c -> nrOfOffersLabel.setText("No. of offers: " + model.getOfferList().size());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
currencyComboBox.setItems(model.getCurrencyListItems());
|
||||
currencyComboBox.setVisibleRowCount(25);
|
||||
currencyComboBox.setItems(model.getTradeCurrencies());
|
||||
currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 25));
|
||||
currencyComboBox.setOnAction(e -> model.onSetTradeCurrency(currencyComboBox.getSelectionModel().getSelectedItem()));
|
||||
|
||||
model.currencyListItems.addListener(currencyListItemsListener);
|
||||
|
||||
applyCurrencyComboBoxSelection();
|
||||
|
||||
currencyComboBox.setOnAction(e -> {
|
||||
CurrencyListItem selectedItem = currencyComboBox.getSelectionModel().getSelectedItem();
|
||||
|
||||
if (selectedItem != null)
|
||||
model.onSetTradeCurrency(selectedItem.tradeCurrency);
|
||||
});
|
||||
if (model.showAllTradeCurrenciesProperty.get())
|
||||
currencyComboBox.getSelectionModel().select(0);
|
||||
else
|
||||
currencyComboBox.getSelectionModel().select(model.getSelectedTradeCurrency());
|
||||
|
||||
priceColumn.sortableProperty().bind(model.showAllTradeCurrenciesProperty.not());
|
||||
volumeColumn.sortableProperty().bind(model.showAllTradeCurrenciesProperty.not());
|
||||
|
@ -242,7 +233,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
if (!tableView.getColumns().contains(marketColumn))
|
||||
tableView.getColumns().add(0, marketColumn);
|
||||
} else {
|
||||
volumeColumn.setText("Amount in " + code + " (min - max)");
|
||||
volumeColumn.setText(code + " (min - max)");
|
||||
priceColumn.setText(formatter.getPriceWithCurrencyCode(code));
|
||||
|
||||
if (tableView.getColumns().contains(marketColumn))
|
||||
|
@ -261,7 +252,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
priceColumn.setSortType((model.getDirection() == Offer.Direction.BUY) ? TableColumn.SortType.ASCENDING : TableColumn.SortType.DESCENDING);
|
||||
|
||||
model.getOfferList().addListener(offerListListener);
|
||||
nrOfOffersLabel.setText("Nr. of offers: " + model.getOfferList().size());
|
||||
nrOfOffersLabel.setText("No. of offers: " + model.getOfferList().size());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -274,18 +265,8 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
priceColumn.sortableProperty().unbind();
|
||||
amountColumn.sortableProperty().unbind();
|
||||
model.getOfferList().removeListener(offerListListener);
|
||||
model.currencyListItems.removeListener(currencyListItemsListener);
|
||||
currencySelectionSubscriber.unsubscribe();
|
||||
}
|
||||
|
||||
private void applyCurrencyComboBoxSelection() {
|
||||
Optional<CurrencyListItem> selectedCurrencyListItem = model.getSelectedCurrencyListItem();
|
||||
UserThread.execute(() -> {
|
||||
if (model.showAllTradeCurrenciesProperty.get() || !selectedCurrencyListItem.isPresent())
|
||||
currencyComboBox.getSelectionModel().select(model.getShowAllCurrencyListItem());
|
||||
else
|
||||
currencyComboBox.getSelectionModel().select(selectedCurrencyListItem.get());
|
||||
});
|
||||
currencySelectionSubscriber.unsubscribe();
|
||||
}
|
||||
|
||||
|
||||
|
@ -312,9 +293,9 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
TradeCurrency selectedTradeCurrency = model.getSelectedTradeCurrency();
|
||||
if (selectedTradeCurrency != null) {
|
||||
Offer.Direction direction = model.getDirection();
|
||||
String preFix = "Create new offer for ";
|
||||
String directionText = direction == Offer.Direction.BUY ? "buying" : "selling";
|
||||
String mirroredDirectionText = direction == Offer.Direction.SELL ? "buying" : "selling";
|
||||
String preFix = "Create new offer to ";
|
||||
String directionText = direction == Offer.Direction.BUY ? "buy" : "sell";
|
||||
String mirroredDirectionText = direction == Offer.Direction.SELL ? "buy" : "sell";
|
||||
String code = selectedTradeCurrency.getCode();
|
||||
if (model.showAllTradeCurrenciesProperty.get())
|
||||
createOfferButton.setText(preFix + directionText + " BTC");
|
||||
|
@ -340,19 +321,19 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
|
||||
private void onCreateOffer() {
|
||||
if (!model.hasPaymentAccount()) {
|
||||
openPopupForMissingAccountSetup("You have not setup a payment account",
|
||||
openPopupForMissingAccountSetup("You have not setup a trading account",
|
||||
"You need to setup a national currency or altcoin account before you can create an offer.\n" +
|
||||
"Do you want to setup an account?", FiatAccountsView.class, "\"Account\"");
|
||||
} else if (!model.hasPaymentAccountForCurrency()) {
|
||||
new Popup().headLine("No payment account for selected currency")
|
||||
.instruction("You don't have a payment account for the selected currency.\n" +
|
||||
"Do you want to create an offer with one of your existing payment accounts?")
|
||||
new Popup().headLine("No trading account for selected currency")
|
||||
.instruction("You don't have a trading account for the selected currency.\n" +
|
||||
"Do you want to create an offer with one of your existing trading accounts?")
|
||||
.actionButtonText("Yes, create offer")
|
||||
.onAction(() -> {
|
||||
createOfferButton.setDisable(true);
|
||||
offerActionHandler.onCreateOffer(model.getSelectedTradeCurrency());
|
||||
})
|
||||
.closeButtonText("Set up a new payment account")
|
||||
.closeButtonText("Set up a new trading account")
|
||||
.onClose(() -> {
|
||||
navigation.setReturnPath(navigation.getCurrentPath());
|
||||
navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class, FiatAccountsView.class);
|
||||
|
@ -376,9 +357,9 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
"You need to setup at least one arbitrator to be able to trade.\n" +
|
||||
"Do you want to do this now?", ArbitratorSelectionView.class, "\"Arbitrator selection\"");
|
||||
} else if (!isPaymentAccountValidForOffer) {
|
||||
openPopupForMissingAccountSetup("No matching payment account",
|
||||
"You don't have a payment account with the payment method required for that offer.\n" +
|
||||
"You need to setup a payment account with that payment method if you want to take this offer.\n" +
|
||||
openPopupForMissingAccountSetup("No matching trading account.",
|
||||
"You don't have a trading account with the payment method required for that offer.\n" +
|
||||
"You need to setup a trading account with that payment method if you want to take this offer.\n" +
|
||||
"Do you want to do this now?", FiatAccountsView.class, "\"Account\"");
|
||||
} else if (!hasSameProtocolVersion) {
|
||||
new Popup().warning("That offer requires a different protocol version as the one used in your " +
|
||||
|
@ -414,7 +395,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
String key = "RemoveOfferWarning";
|
||||
if (model.preferences.showAgain(key))
|
||||
new Popup().warning("Are you sure you want to remove that offer?\n" +
|
||||
"The offer fee you have paid will be lost if you remove that offer.")
|
||||
"The offer fee you " + model.formatter.formatCoinWithCode(FeePolicy.getCreateOfferFee()) + " will be lost if you remove that offer.")
|
||||
.actionButtonText("Remove offer")
|
||||
.onAction(() -> doRemoveOffer(offer))
|
||||
.closeButtonText("Don't remove the offer")
|
||||
|
@ -432,7 +413,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
String key = "WithdrawFundsAfterRemoveOfferInfo";
|
||||
model.onRemoveOpenOffer(offer,
|
||||
() -> {
|
||||
log.debug("Remove offer was successful");
|
||||
log.debug("Remove offer was successful.");
|
||||
if (model.preferences.showAgain(key))
|
||||
new Popup().instruction("You can withdraw the funds you paid in from the \"Fund/Available for withdrawal\" screen.")
|
||||
.actionButtonText("Go to \"Funds/Available for withdrawal\"")
|
||||
|
@ -461,7 +442,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private TableColumn<OfferBookListItem, OfferBookListItem> getAmountColumn() {
|
||||
TableColumn<OfferBookListItem, OfferBookListItem> column = new TableColumn<OfferBookListItem, OfferBookListItem>("Amount in BTC (min - max)") {
|
||||
TableColumn<OfferBookListItem, OfferBookListItem> column = new TableColumn<OfferBookListItem, OfferBookListItem>("BTC (min - max)") {
|
||||
{
|
||||
setMinWidth(150);
|
||||
}
|
||||
|
@ -491,8 +472,8 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
private TableColumn<OfferBookListItem, OfferBookListItem> getMarketColumn() {
|
||||
TableColumn<OfferBookListItem, OfferBookListItem> column = new TableColumn<OfferBookListItem, OfferBookListItem>("Market") {
|
||||
{
|
||||
setMinWidth(130);
|
||||
setMaxWidth(130);
|
||||
setMinWidth(120); //130
|
||||
// setMaxWidth(130);
|
||||
}
|
||||
};
|
||||
column.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
|
@ -522,7 +503,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
private TableColumn<OfferBookListItem, OfferBookListItem> getPriceColumn() {
|
||||
TableColumn<OfferBookListItem, OfferBookListItem> column = new TableColumn<OfferBookListItem, OfferBookListItem>() {
|
||||
{
|
||||
setMinWidth(130);
|
||||
setMinWidth(120); //130
|
||||
}
|
||||
};
|
||||
column.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
|
@ -572,7 +553,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
private TableColumn<OfferBookListItem, OfferBookListItem> getVolumeColumn() {
|
||||
TableColumn<OfferBookListItem, OfferBookListItem> column = new TableColumn<OfferBookListItem, OfferBookListItem>() {
|
||||
{
|
||||
setMinWidth(130);
|
||||
setMinWidth(125); //130
|
||||
}
|
||||
};
|
||||
column.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
|
@ -621,7 +602,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
private TableColumn<OfferBookListItem, OfferBookListItem> getPaymentMethodColumn() {
|
||||
TableColumn<OfferBookListItem, OfferBookListItem> column = new TableColumn<OfferBookListItem, OfferBookListItem>("Payment method") {
|
||||
{
|
||||
setMinWidth(120);
|
||||
setMinWidth(125); //120
|
||||
}
|
||||
};
|
||||
column.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
|
@ -675,8 +656,8 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
|
||||
{
|
||||
button.setGraphic(iconView);
|
||||
button.setMinWidth(150);
|
||||
button.setMaxWidth(150);
|
||||
button.setMinWidth(130);
|
||||
button.setMaxWidth(130);
|
||||
button.setGraphicTextGap(10);
|
||||
}
|
||||
|
||||
|
@ -684,10 +665,10 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
public void updateItem(final OfferBookListItem newItem, boolean empty) {
|
||||
super.updateItem(newItem, empty);
|
||||
|
||||
TableRow tableRow = getTableRow();
|
||||
if (newItem != null && !empty) {
|
||||
final Offer offer = newItem.getOffer();
|
||||
boolean myOffer = model.isMyOffer(offer);
|
||||
TableRow tableRow = getTableRow();
|
||||
if (tableRow != null) {
|
||||
isPaymentAccountValidForOffer = model.isAnyPaymentAccountValidForOffer(offer);
|
||||
hasMatchingArbitrator = model.hasMatchingArbitrator(offer);
|
||||
|
@ -706,7 +687,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
if (isTradable) {
|
||||
// set first row button as default
|
||||
button.setDefaultButton(getIndex() == 0);
|
||||
tableRow.setOnMouseClicked(null);
|
||||
tableRow.setOnMousePressed(null);
|
||||
} else {
|
||||
button.setDefaultButton(false);
|
||||
tableRow.setOnMousePressed(e -> {
|
||||
|
@ -749,10 +730,9 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
setGraphic(null);
|
||||
if (button != null)
|
||||
button.setOnAction(null);
|
||||
TableRow tableRow = getTableRow();
|
||||
if (tableRow != null) {
|
||||
tableRow.setOpacity(1);
|
||||
tableRow.setOnMouseClicked(null);
|
||||
tableRow.setOnMousePressed(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -786,8 +766,8 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
String hostName = newItem.getOffer().getOwnerNodeAddress().hostName;
|
||||
int numPastTrades = model.getNumPastTrades(newItem.getOffer());
|
||||
boolean hasTraded = numPastTrades > 0;
|
||||
String tooltipText = hasTraded ? "Offerers onion address: " + hostName + "\n" +
|
||||
"You have already traded " + numPastTrades + " times with that offerer." : "Offerers onion address: " + hostName;
|
||||
String tooltipText = hasTraded ? "Offerer's onion address: " + hostName + "\n" +
|
||||
"You have already traded " + numPastTrades + " times with that offerer." : "Offerer's onion address: " + hostName;
|
||||
Node identIcon = new PeerInfoIcon(hostName, tooltipText, numPastTrades, privateNotificationManager, newItem.getOffer());
|
||||
setPadding(new Insets(-2, 0, -2, 0));
|
||||
if (identIcon != null)
|
||||
|
|
|
@ -30,7 +30,6 @@ import io.bitsquare.gui.main.MainView;
|
|||
import io.bitsquare.gui.main.settings.SettingsView;
|
||||
import io.bitsquare.gui.main.settings.preferences.PreferencesView;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.gui.util.CurrencyListItem;
|
||||
import io.bitsquare.gui.util.GUIUtil;
|
||||
import io.bitsquare.locale.*;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
|
@ -59,7 +58,6 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -80,10 +78,10 @@ class OfferBookViewModel extends ActivatableViewModel {
|
|||
|
||||
private final FilteredList<OfferBookListItem> filteredItems;
|
||||
private final SortedList<OfferBookListItem> sortedItems;
|
||||
private final ListChangeListener<TradeCurrency> tradeCurrencyListChangeListener;
|
||||
private TradeCurrency selectedTradeCurrency;
|
||||
private final ListChangeListener<OfferBookListItem> offerBookListItemsListener;
|
||||
final ObservableList<CurrencyListItem> currencyListItems = FXCollections.observableArrayList();
|
||||
private CurrencyListItem showAllCurrencyListItem = new CurrencyListItem(new CryptoCurrency(GUIUtil.SHOW_ALL_FLAG, GUIUtil.SHOW_ALL_FLAG), -1);
|
||||
private final ObservableList<TradeCurrency> allTradeCurrencies = FXCollections.observableArrayList();
|
||||
|
||||
private Offer.Direction direction;
|
||||
|
||||
private final StringProperty btcCode = new SimpleStringProperty();
|
||||
|
@ -122,16 +120,19 @@ class OfferBookViewModel extends ActivatableViewModel {
|
|||
this.formatter = formatter;
|
||||
|
||||
offerBookListItems = offerBook.getOfferBookListItems();
|
||||
offerBookListItemsListener = c -> fillTradeCurrencies();
|
||||
|
||||
this.filteredItems = new FilteredList<>(offerBookListItems);
|
||||
this.sortedItems = new SortedList<>(filteredItems);
|
||||
|
||||
tradeCurrencyListChangeListener = c -> {
|
||||
tradeCurrencyCodes = preferences.getTradeCurrenciesAsObservable().stream().map(e -> e.getCode()).collect(Collectors.toSet());
|
||||
fillAllTradeCurrencies();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
fillTradeCurrencies();
|
||||
offerBookListItems.addListener(offerBookListItemsListener);
|
||||
tradeCurrencyCodes = preferences.getTradeCurrenciesAsObservable().stream().map(e -> e.getCode()).collect(Collectors.toSet());
|
||||
|
||||
String code = direction == Offer.Direction.BUY ? preferences.getBuyScreenCurrencyCode() : preferences.getSellScreenCurrencyCode();
|
||||
if (code != null && !code.equals("SHOW_ALL_FLAG") && !code.isEmpty() && CurrencyUtil.getTradeCurrency(code).isPresent()) {
|
||||
|
@ -145,7 +146,9 @@ class OfferBookViewModel extends ActivatableViewModel {
|
|||
|
||||
setPriceFeedType();
|
||||
|
||||
fillAllTradeCurrencies();
|
||||
btcCode.bind(preferences.btcDenominationProperty());
|
||||
preferences.getTradeCurrenciesAsObservable().addListener(tradeCurrencyListChangeListener);
|
||||
offerBook.fillOfferBookListItems();
|
||||
applyFilterPredicate();
|
||||
setMarketPriceFeedCurrency();
|
||||
|
@ -154,9 +157,10 @@ class OfferBookViewModel extends ActivatableViewModel {
|
|||
@Override
|
||||
protected void deactivate() {
|
||||
btcCode.unbind();
|
||||
offerBookListItems.removeListener(offerBookListItemsListener);
|
||||
preferences.getTradeCurrenciesAsObservable().removeListener(tradeCurrencyListChangeListener);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -227,6 +231,10 @@ class OfferBookViewModel extends ActivatableViewModel {
|
|||
return direction;
|
||||
}
|
||||
|
||||
public ObservableList<TradeCurrency> getTradeCurrencies() {
|
||||
return allTradeCurrencies;
|
||||
}
|
||||
|
||||
boolean isBootstrapped() {
|
||||
return p2PService.isBootstrapped();
|
||||
}
|
||||
|
@ -241,19 +249,6 @@ class OfferBookViewModel extends ActivatableViewModel {
|
|||
return list;
|
||||
}
|
||||
|
||||
ObservableList<CurrencyListItem> getCurrencyListItems() {
|
||||
return currencyListItems;
|
||||
}
|
||||
|
||||
Optional<CurrencyListItem> getSelectedCurrencyListItem() {
|
||||
return currencyListItems.stream().filter(e -> tradeCurrencyCode.get() != null && e.tradeCurrency.getCode().equals(tradeCurrencyCode.get())).findAny();
|
||||
}
|
||||
|
||||
CurrencyListItem getShowAllCurrencyListItem() {
|
||||
return showAllCurrencyListItem;
|
||||
}
|
||||
|
||||
|
||||
String getAmount(OfferBookListItem item) {
|
||||
Offer offer = item.getOffer();
|
||||
Coin amount = offer.getAmount();
|
||||
|
@ -326,14 +321,14 @@ class OfferBookViewModel extends ActivatableViewModel {
|
|||
String bankId = offer.getBankId();
|
||||
if (bankId != null && !bankId.equals("null")) {
|
||||
if (BankUtil.isBankIdRequired(methodCountryCode))
|
||||
result += "\nOfferers bank ID: " + bankId;
|
||||
result += "\nOfferer's bank ID: " + bankId;
|
||||
else if (BankUtil.isBankNameRequired(methodCountryCode))
|
||||
result += "\nOfferers bank name: " + bankId;
|
||||
result += "\nOfferer's bank name: " + bankId;
|
||||
}
|
||||
}
|
||||
|
||||
if (methodCountryCode != null)
|
||||
result += "\nOfferers seat of bank country: " + CountryUtil.getNameByCode(methodCountryCode);
|
||||
result += "\nOfferer's seat of bank country: " + CountryUtil.getNameByCode(methodCountryCode);
|
||||
|
||||
List<String> acceptedCountryCodes = offer.getAcceptedCountryCodes();
|
||||
List<String> acceptedBanks = offer.getAcceptedBankIds();
|
||||
|
@ -381,24 +376,12 @@ class OfferBookViewModel extends ActivatableViewModel {
|
|||
priceFeedService.setType(direction == Offer.Direction.BUY ? PriceFeedService.Type.ASK : PriceFeedService.Type.BID);
|
||||
}
|
||||
|
||||
private void fillTradeCurrencies() {
|
||||
// Don't use a set as we need all entries
|
||||
Offer.Direction mirroredDirection = direction == Offer.Direction.BUY ? Offer.Direction.SELL : Offer.Direction.BUY;
|
||||
List<TradeCurrency> tradeCurrencyList = offerBookListItems.stream()
|
||||
.filter(e -> e.getOffer().getDirection() == mirroredDirection)
|
||||
.map(e -> {
|
||||
Optional<TradeCurrency> tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(e.getOffer().getCurrencyCode());
|
||||
if (tradeCurrencyOptional.isPresent())
|
||||
return tradeCurrencyOptional.get();
|
||||
else
|
||||
return null;
|
||||
|
||||
})
|
||||
.filter(e -> e != null)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
GUIUtil.fillCurrencyListItems(tradeCurrencyList, currencyListItems, showAllCurrencyListItem, preferences);
|
||||
tradeCurrencyCodes = currencyListItems.stream().map(e -> e.tradeCurrency.getCode()).collect(Collectors.toSet());
|
||||
private void fillAllTradeCurrencies() {
|
||||
allTradeCurrencies.clear();
|
||||
// Used for ignoring filter (show all)
|
||||
allTradeCurrencies.add(new CryptoCurrency(GUIUtil.SHOW_ALL_FLAG, GUIUtil.SHOW_ALL_FLAG));
|
||||
allTradeCurrencies.addAll(preferences.getTradeCurrenciesAsObservable());
|
||||
allTradeCurrencies.add(new CryptoCurrency(GUIUtil.EDIT_FLAG, GUIUtil.EDIT_FLAG));
|
||||
}
|
||||
|
||||
|
||||
|
@ -433,7 +416,7 @@ class OfferBookViewModel extends ActivatableViewModel {
|
|||
boolean currencyResult;
|
||||
final String currencyCode = offer.getCurrencyCode();
|
||||
if (showAllTradeCurrenciesProperty.get()) {
|
||||
currencyResult = true;
|
||||
currencyResult = tradeCurrencyCodes.contains(currencyCode);
|
||||
} else
|
||||
currencyResult = currencyCode.equals(selectedTradeCurrency.getCode());
|
||||
|
||||
|
|
|
@ -223,7 +223,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
directionLabel.setId("direction-icon-label-buy");
|
||||
|
||||
takeOfferButton.setId("buy-button-big");
|
||||
takeOfferButton.setText("Review offer for buying bitcoin");
|
||||
takeOfferButton.setText("Review offer to buy bitcoin");
|
||||
nextButton.setId("buy-button");
|
||||
} else {
|
||||
imageView.setId("image-sell-large");
|
||||
|
@ -231,7 +231,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
|
||||
takeOfferButton.setId("sell-button-big");
|
||||
nextButton.setId("sell-button");
|
||||
takeOfferButton.setText("Review offer for selling bitcoin");
|
||||
takeOfferButton.setText("Review offer to sell bitcoin");
|
||||
}
|
||||
|
||||
boolean showComboBox = model.getPossiblePaymentAccounts().size() > 1;
|
||||
|
@ -350,14 +350,11 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
"- Trading fee: " + model.getTakerFee() + "\n" +
|
||||
"- Bitcoin mining fee: " + model.getNetworkFee() + "\n\n" +
|
||||
|
||||
"For funding you can choose between 2 options:\n" +
|
||||
"- Transfer fund from your Bitsquare wallet OR\n" +
|
||||
"- Transfer fund from any external wallet\n\n" +
|
||||
"You can choose between two options when funding your trade:\n" +
|
||||
"- Use your Bitsquare wallet (convenient, but transactions may be linkable) OR\n" +
|
||||
"- Transfer from an external wallet (potentially more private)\n\n" +
|
||||
|
||||
"If you prefer a higher level of privacy you should use for each trade a distinct funding transaction using the external wallet option.\n" +
|
||||
"If you prefer convenience using the Bitsquare wallet for several trades might be your preferred option.\n\n" +
|
||||
|
||||
"You can see all the details for funding when you close that popup.")
|
||||
"You will see all funding options and details after closing this popup.")
|
||||
.dontShowAgainId(key, preferences)
|
||||
.show();
|
||||
}
|
||||
|
@ -623,12 +620,12 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, gridRow, 2, "Payment info");
|
||||
GridPane.setColumnSpan(titledGroupBg, 3);
|
||||
|
||||
Tuple2<Label, ComboBox> tuple = addLabelComboBox(gridPane, gridRow, "Payment account:", Layout.FIRST_ROW_DISTANCE);
|
||||
Tuple2<Label, ComboBox> tuple = addLabelComboBox(gridPane, gridRow, "Trading account:", Layout.FIRST_ROW_DISTANCE);
|
||||
paymentAccountsLabel = tuple.first;
|
||||
paymentAccountsLabel.setVisible(false);
|
||||
paymentAccountsLabel.setManaged(false);
|
||||
paymentAccountsComboBox = tuple.second;
|
||||
paymentAccountsComboBox.setPromptText("Select payment account");
|
||||
paymentAccountsComboBox.setPromptText("Select trading account");
|
||||
paymentAccountsComboBox.setConverter(new StringConverter<PaymentAccount>() {
|
||||
@Override
|
||||
public String toString(PaymentAccount paymentAccount) {
|
||||
|
|
|
@ -128,7 +128,7 @@ public class ContractWindow extends Overlay<ContractWindow> {
|
|||
contract.getBuyerPayoutAddressString() + " / " + contract.getSellerPayoutAddressString()).second.setMouseTransparent(false);
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "Network address BTC buyer / BTC seller:", contract.getBuyerNodeAddress().getFullAddress() + " / " + contract.getSellerNodeAddress().getFullAddress());
|
||||
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "Nr. of disputes BTC buyer / BTC seller:", disputeManager.getNrOfDisputes(true, contract) + " / " + disputeManager.getNrOfDisputes(false, contract));
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "No. of disputes BTC buyer / BTC seller:", disputeManager.getNrOfDisputes(true, contract) + " / " + disputeManager.getNrOfDisputes(false, contract));
|
||||
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "BTC buyer payment details:",
|
||||
BSResources.get(contract.getBuyerPaymentAccountContractData().getPaymentDetails())).second.setMouseTransparent(false);
|
||||
|
|
|
@ -27,6 +27,7 @@ import io.bitsquare.btc.WalletService;
|
|||
import io.bitsquare.btc.exceptions.TransactionVerificationException;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.util.Tuple2;
|
||||
import io.bitsquare.gui.components.InputTextField;
|
||||
import io.bitsquare.gui.main.overlays.Overlay;
|
||||
import io.bitsquare.gui.main.overlays.popups.Popup;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
|
@ -69,18 +70,23 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
private Optional<Runnable> finalizeDisputeHandlerOptional = Optional.empty();
|
||||
private ToggleGroup tradeAmountToggleGroup;
|
||||
private DisputeResult disputeResult;
|
||||
private RadioButton buyerIsWinnerRadioButton, sellerIsWinnerRadioButton, shareRadioButton, loserPaysFeeRadioButton, splitFeeRadioButton,
|
||||
private RadioButton buyerIsWinnerRadioButton, sellerIsWinnerRadioButton, shareRadioButton, customRadioButton, loserPaysFeeRadioButton, splitFeeRadioButton,
|
||||
waiveFeeRadioButton, reasonWasBugRadioButton, reasonWasUsabilityIssueRadioButton, reasonProtocolViolationRadioButton, reasonNoReplyRadioButton, reasonWasScamRadioButton, reasonWasOtherRadioButton;
|
||||
private Optional<Dispute> peersDisputeOptional;
|
||||
private Coin arbitratorPayoutAmount, winnerPayoutAmount, loserPayoutAmount, stalematePayoutAmount;
|
||||
private ToggleGroup feeToggleGroup, reasonToggleGroup;
|
||||
private String role;
|
||||
private TextArea summaryNotesTextArea;
|
||||
private ObjectBinding<Tuple2<DisputeResult.DisputeFeePolicy, Toggle>> feePaymentPolicyChanged;
|
||||
private ChangeListener<Tuple2<DisputeResult.DisputeFeePolicy, Toggle>> feePaymentPolicyListener;
|
||||
private ChangeListener<Boolean> shareRadioButtonSelectedListener;
|
||||
private ChangeListener<Toggle> feeToggleSelectionListener, reasonToggleSelectionListener;
|
||||
|
||||
// keep a reference to not get GCed
|
||||
private ObjectBinding<Tuple2<DisputeResult.DisputeFeePolicy, Toggle>> feePaymentPolicyChanged;
|
||||
|
||||
private ChangeListener<Tuple2<DisputeResult.DisputeFeePolicy, Toggle>> feePaymentPolicyListener;
|
||||
private ChangeListener<Boolean> shareRadioButtonSelectedListener, customRadioButtonSelectedListener;
|
||||
private ChangeListener<Toggle> feeToggleSelectionListener, reasonToggleSelectionListener;
|
||||
private InputTextField buyerPayoutAmountInputTextField, sellerPayoutAmountInputTextField, arbitratorPayoutAmountInputTextField;
|
||||
private ChangeListener<String> buyerPayoutAmountListener, sellerPayoutAmountListener, arbitratorPayoutAmountListener;
|
||||
private CheckBox isLoserPublisherCheckBox;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -130,6 +136,11 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
|
||||
if (reasonToggleGroup != null)
|
||||
reasonToggleGroup.selectedToggleProperty().removeListener(reasonToggleSelectionListener);
|
||||
|
||||
if (customRadioButton != null)
|
||||
customRadioButton.selectedProperty().removeListener(customRadioButtonSelectedListener);
|
||||
|
||||
removePayoutAmountListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -172,6 +183,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
|
||||
addTradeAmountPayoutControls();
|
||||
addFeeControls();
|
||||
addPayoutAmountTextFields();
|
||||
addReasonControls();
|
||||
|
||||
boolean applyPeersDisputeResult = peersDisputeOptional.isPresent() && peersDisputeOptional.get().isClosed();
|
||||
|
@ -183,6 +195,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
disputeResult.setArbitratorPayoutAmount(peersDisputeResult.getArbitratorPayoutAmount());
|
||||
disputeResult.setDisputeFeePolicy(peersDisputeResult.getDisputeFeePolicy());
|
||||
disputeResult.setWinner(peersDisputeResult.getWinner());
|
||||
disputeResult.setLoserIsPublisher(peersDisputeResult.isLoserPublisher());
|
||||
disputeResult.setReason(peersDisputeResult.getReason());
|
||||
disputeResult.setSummaryNotes(peersDisputeResult.summaryNotesProperty().get());
|
||||
|
||||
|
@ -195,10 +208,18 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
buyerIsWinnerRadioButton.setDisable(true);
|
||||
sellerIsWinnerRadioButton.setDisable(true);
|
||||
shareRadioButton.setDisable(true);
|
||||
customRadioButton.setDisable(true);
|
||||
loserPaysFeeRadioButton.setDisable(true);
|
||||
splitFeeRadioButton.setDisable(true);
|
||||
waiveFeeRadioButton.setDisable(true);
|
||||
|
||||
buyerPayoutAmountInputTextField.setDisable(true);
|
||||
sellerPayoutAmountInputTextField.setDisable(true);
|
||||
arbitratorPayoutAmountInputTextField.setDisable(true);
|
||||
buyerPayoutAmountInputTextField.setEditable(false);
|
||||
sellerPayoutAmountInputTextField.setEditable(false);
|
||||
arbitratorPayoutAmountInputTextField.setEditable(false);
|
||||
|
||||
reasonWasBugRadioButton.setDisable(true);
|
||||
reasonWasUsabilityIssueRadioButton.setDisable(true);
|
||||
reasonProtocolViolationRadioButton.setDisable(true);
|
||||
|
@ -206,6 +227,9 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
reasonWasScamRadioButton.setDisable(true);
|
||||
reasonWasOtherRadioButton.setDisable(true);
|
||||
|
||||
isLoserPublisherCheckBox.setDisable(true);
|
||||
isLoserPublisherCheckBox.setSelected(peersDisputeResult.isLoserPublisher());
|
||||
|
||||
calculatePayoutAmounts(disputeResult.getDisputeFeePolicy());
|
||||
applyTradeAmountRadioButtonStates();
|
||||
} else {
|
||||
|
@ -214,10 +238,10 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
() -> new Tuple2<>(disputeResult.disputeFeePolicyProperty().get(), tradeAmountToggleGroup.selectedToggleProperty().get()),
|
||||
disputeResult.disputeFeePolicyProperty(),
|
||||
tradeAmountToggleGroup.selectedToggleProperty());
|
||||
feePaymentPolicyListener = (observable, oldValue, newValue) -> {
|
||||
applyPayoutAmounts(newValue.first, newValue.second);
|
||||
};
|
||||
feePaymentPolicyListener = (observable, oldValue, newValue) -> applyPayoutAmounts(newValue.first, newValue.second);
|
||||
feePaymentPolicyChanged.addListener(feePaymentPolicyListener);
|
||||
|
||||
isLoserPublisherCheckBox.setSelected(false);
|
||||
}
|
||||
|
||||
setFeeRadioButtonState();
|
||||
|
@ -229,7 +253,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
|
||||
private void addInfoPane() {
|
||||
Contract contract = dispute.getContract();
|
||||
addTitledGroupBg(gridPane, ++rowIndex, 12, "Summary");
|
||||
addTitledGroupBg(gridPane, ++rowIndex, 16, "Summary");
|
||||
addLabelTextField(gridPane, rowIndex, "Trade ID:", dispute.getShortTradeId(), Layout.FIRST_ROW_DISTANCE);
|
||||
addLabelTextField(gridPane, ++rowIndex, "Ticket opening date:", formatter.formatDateTime(dispute.getOpeningDate()));
|
||||
if (dispute.isDisputeOpenerIsOfferer()) {
|
||||
|
@ -243,7 +267,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
else
|
||||
role = "BTC Seller/taker";
|
||||
}
|
||||
addLabelTextField(gridPane, ++rowIndex, "Traders role:", role);
|
||||
addLabelTextField(gridPane, ++rowIndex, "Trader's role:", role);
|
||||
addLabelTextField(gridPane, ++rowIndex, "Trade amount:", formatter.formatCoinWithCode(contract.getTradeAmount()));
|
||||
addLabelTextField(gridPane, ++rowIndex, "Trade price:", formatter.formatPrice(contract.getTradePrice()));
|
||||
addLabelTextField(gridPane, ++rowIndex, "Trade volume:", formatter.formatVolumeWithCode(new ExchangeRate(contract.getTradePrice()).coinToFiat(contract.getTradeAmount())));
|
||||
|
@ -277,18 +301,20 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
buyerIsWinnerRadioButton = new RadioButton("BTC buyer gets trade amount payout");
|
||||
sellerIsWinnerRadioButton = new RadioButton("BTC seller gets trade amount payout");
|
||||
shareRadioButton = new RadioButton("Both gets half trade amount payout");
|
||||
customRadioButton = new RadioButton("Custom payout");
|
||||
VBox radioButtonPane = new VBox();
|
||||
radioButtonPane.setSpacing(20);
|
||||
radioButtonPane.getChildren().addAll(buyerIsWinnerRadioButton, sellerIsWinnerRadioButton, shareRadioButton);
|
||||
radioButtonPane.setSpacing(10);
|
||||
radioButtonPane.getChildren().addAll(buyerIsWinnerRadioButton, sellerIsWinnerRadioButton, shareRadioButton, customRadioButton);
|
||||
GridPane.setRowIndex(radioButtonPane, rowIndex);
|
||||
GridPane.setColumnIndex(radioButtonPane, 1);
|
||||
GridPane.setMargin(radioButtonPane, new Insets(10, 0, 10, 0));
|
||||
GridPane.setMargin(radioButtonPane, new Insets(10, 0, 0, 0));
|
||||
gridPane.getChildren().add(radioButtonPane);
|
||||
|
||||
tradeAmountToggleGroup = new ToggleGroup();
|
||||
buyerIsWinnerRadioButton.setToggleGroup(tradeAmountToggleGroup);
|
||||
sellerIsWinnerRadioButton.setToggleGroup(tradeAmountToggleGroup);
|
||||
shareRadioButton.setToggleGroup(tradeAmountToggleGroup);
|
||||
customRadioButton.setToggleGroup(tradeAmountToggleGroup);
|
||||
|
||||
shareRadioButtonSelectedListener = (observable, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
|
@ -304,6 +330,91 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
loserPaysFeeRadioButton.setDisable(newValue);
|
||||
};
|
||||
shareRadioButton.selectedProperty().addListener(shareRadioButtonSelectedListener);
|
||||
|
||||
buyerPayoutAmountListener = (observable1, oldValue1, newValue1) -> applyCustomAmounts(buyerPayoutAmountInputTextField);
|
||||
sellerPayoutAmountListener = (observable1, oldValue1, newValue1) -> applyCustomAmounts(sellerPayoutAmountInputTextField);
|
||||
arbitratorPayoutAmountListener = (observable1, oldValue1, newValue1) -> applyCustomAmounts(arbitratorPayoutAmountInputTextField);
|
||||
|
||||
customRadioButtonSelectedListener = (observable, oldValue, newValue) -> {
|
||||
buyerPayoutAmountInputTextField.setEditable(newValue);
|
||||
sellerPayoutAmountInputTextField.setEditable(newValue);
|
||||
arbitratorPayoutAmountInputTextField.setEditable(newValue);
|
||||
|
||||
loserPaysFeeRadioButton.setDisable(newValue);
|
||||
splitFeeRadioButton.setDisable(newValue);
|
||||
waiveFeeRadioButton.setDisable(newValue);
|
||||
|
||||
if (newValue) {
|
||||
buyerPayoutAmountInputTextField.textProperty().addListener(buyerPayoutAmountListener);
|
||||
sellerPayoutAmountInputTextField.textProperty().addListener(sellerPayoutAmountListener);
|
||||
arbitratorPayoutAmountInputTextField.textProperty().addListener(arbitratorPayoutAmountListener);
|
||||
} else {
|
||||
removePayoutAmountListeners();
|
||||
}
|
||||
};
|
||||
customRadioButton.selectedProperty().addListener(customRadioButtonSelectedListener);
|
||||
}
|
||||
|
||||
private void removePayoutAmountListeners() {
|
||||
if (buyerPayoutAmountInputTextField != null && buyerPayoutAmountListener != null)
|
||||
buyerPayoutAmountInputTextField.textProperty().removeListener(buyerPayoutAmountListener);
|
||||
|
||||
if (sellerPayoutAmountInputTextField != null && sellerPayoutAmountListener != null)
|
||||
sellerPayoutAmountInputTextField.textProperty().removeListener(sellerPayoutAmountListener);
|
||||
|
||||
if (arbitratorPayoutAmountInputTextField != null && arbitratorPayoutAmountListener != null)
|
||||
arbitratorPayoutAmountInputTextField.textProperty().removeListener(arbitratorPayoutAmountListener);
|
||||
}
|
||||
|
||||
private boolean isPayoutAmountValid() {
|
||||
Coin buyerAmount = formatter.parseToCoin(buyerPayoutAmountInputTextField.getText());
|
||||
Coin sellerAmount = formatter.parseToCoin(sellerPayoutAmountInputTextField.getText());
|
||||
Coin arbitratorAmount = formatter.parseToCoin(arbitratorPayoutAmountInputTextField.getText());
|
||||
Coin securityDeposit = FeePolicy.getSecurityDeposit();
|
||||
Coin tradeAmount = dispute.getContract().getTradeAmount();
|
||||
Coin available = tradeAmount.add(securityDeposit).add(securityDeposit);
|
||||
Coin totalAmount = buyerAmount.add(sellerAmount).add(arbitratorAmount);
|
||||
return (totalAmount.compareTo(available) == 0);
|
||||
}
|
||||
|
||||
private void applyCustomAmounts(InputTextField inputTextField) {
|
||||
Coin securityDeposit = FeePolicy.getSecurityDeposit();
|
||||
Coin tradeAmount = dispute.getContract().getTradeAmount();
|
||||
|
||||
Coin buyerAmount = formatter.parseToCoin(buyerPayoutAmountInputTextField.getText());
|
||||
Coin sellerAmount = formatter.parseToCoin(sellerPayoutAmountInputTextField.getText());
|
||||
Coin arbitratorAmount = formatter.parseToCoin(arbitratorPayoutAmountInputTextField.getText());
|
||||
|
||||
Coin available = tradeAmount.add(securityDeposit).add(securityDeposit);
|
||||
Coin totalAmount = buyerAmount.add(sellerAmount).add(arbitratorAmount);
|
||||
|
||||
if (totalAmount.compareTo(available) > 0) {
|
||||
new Popup<>().warning("Amount entered exceeds available amount of " + available.toFriendlyString() + ".\n" +
|
||||
"We adjust this input field to the max possible value.")
|
||||
.show();
|
||||
|
||||
if (inputTextField == buyerPayoutAmountInputTextField) {
|
||||
buyerAmount = available.subtract(sellerAmount).subtract(arbitratorAmount);
|
||||
inputTextField.setText(formatter.formatCoin(buyerAmount));
|
||||
} else if (inputTextField == sellerPayoutAmountInputTextField) {
|
||||
sellerAmount = available.subtract(buyerAmount).subtract(arbitratorAmount);
|
||||
inputTextField.setText(formatter.formatCoin(sellerAmount));
|
||||
} else if (inputTextField == arbitratorPayoutAmountInputTextField) {
|
||||
arbitratorAmount = available.subtract(sellerAmount).subtract(buyerAmount);
|
||||
inputTextField.setText(formatter.formatCoin(arbitratorAmount));
|
||||
}
|
||||
}
|
||||
|
||||
disputeResult.setBuyerPayoutAmount(buyerAmount);
|
||||
disputeResult.setSellerPayoutAmount(sellerAmount);
|
||||
disputeResult.setArbitratorPayoutAmount(arbitratorAmount);
|
||||
|
||||
if (buyerAmount.compareTo(sellerAmount) == 0)
|
||||
disputeResult.setWinner(DisputeResult.Winner.STALE_MATE);
|
||||
else if (buyerAmount.compareTo(sellerAmount) > 0)
|
||||
disputeResult.setWinner(DisputeResult.Winner.BUYER);
|
||||
else
|
||||
disputeResult.setWinner(DisputeResult.Winner.SELLER);
|
||||
}
|
||||
|
||||
private void addFeeControls() {
|
||||
|
@ -340,6 +451,19 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
feeToggleGroup.selectToggle(waiveFeeRadioButton);
|
||||
}
|
||||
|
||||
private void addPayoutAmountTextFields() {
|
||||
buyerPayoutAmountInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "Buyer's payout amount:").second;
|
||||
buyerPayoutAmountInputTextField.setEditable(false);
|
||||
|
||||
sellerPayoutAmountInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "Seller's payout amount:").second;
|
||||
sellerPayoutAmountInputTextField.setEditable(false);
|
||||
|
||||
arbitratorPayoutAmountInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "Arbitrator's payout amount:").second;
|
||||
arbitratorPayoutAmountInputTextField.setEditable(false);
|
||||
|
||||
isLoserPublisherCheckBox = addLabelCheckBox(gridPane, ++rowIndex, "Use loser as publisher:").second;
|
||||
}
|
||||
|
||||
private void setFeeRadioButtonState() {
|
||||
switch (disputeResult.getDisputeFeePolicy()) {
|
||||
case LOSER:
|
||||
|
@ -432,6 +556,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
summaryNotesTextArea = new TextArea();
|
||||
summaryNotesTextArea.setPromptText("Add summary notes");
|
||||
summaryNotesTextArea.setWrapText(true);
|
||||
summaryNotesTextArea.setPrefHeight(50);
|
||||
summaryNotesTextArea.textProperty().bindBidirectional(disputeResult.summaryNotesProperty());
|
||||
GridPane.setRowIndex(summaryNotesTextArea, rowIndex);
|
||||
GridPane.setColumnIndex(summaryNotesTextArea, 1);
|
||||
|
@ -444,9 +569,13 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
closeTicketButton.disableProperty().bind(Bindings.createBooleanBinding(
|
||||
() -> tradeAmountToggleGroup.getSelectedToggle() == null
|
||||
|| summaryNotesTextArea.getText() == null
|
||||
|| summaryNotesTextArea.getText().length() == 0,
|
||||
|| summaryNotesTextArea.getText().length() == 0
|
||||
|| !isPayoutAmountValid(),
|
||||
tradeAmountToggleGroup.selectedToggleProperty(),
|
||||
summaryNotesTextArea.textProperty()));
|
||||
summaryNotesTextArea.textProperty(),
|
||||
buyerPayoutAmountInputTextField.textProperty(),
|
||||
sellerPayoutAmountInputTextField.textProperty(),
|
||||
arbitratorPayoutAmountInputTextField.textProperty()));
|
||||
|
||||
Button cancelButton = tuple.second;
|
||||
|
||||
|
@ -457,7 +586,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
AddressEntry arbitratorAddressEntry = walletService.getOrCreateAddressEntry(AddressEntry.Context.ARBITRATOR);
|
||||
disputeResult.setArbitratorAddressAsString(arbitratorAddressEntry.getAddressString());
|
||||
disputeResult.setArbitratorPubKey(arbitratorAddressEntry.getPubKey());
|
||||
|
||||
|
||||
/* byte[] depositTxSerialized,
|
||||
Coin buyerPayoutAmount,
|
||||
Coin sellerPayoutAmount,
|
||||
|
@ -486,6 +615,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
closeTicketButton.disableProperty().unbind();
|
||||
dispute.setDisputeResult(disputeResult);
|
||||
|
||||
disputeResult.setLoserIsPublisher(isLoserPublisherCheckBox.isSelected());
|
||||
disputeResult.setCloseDate(new Date());
|
||||
String text = "Ticket closed on " + formatter.formatDateTime(disputeResult.getCloseDate()) +
|
||||
"\n\nSummary:" +
|
||||
|
@ -494,7 +624,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
"\n" + role + " did screencast or video: " + formatter.booleanToYesNo(disputeResult.screenCastProperty().get()) +
|
||||
"\nPayout amount for BTC buyer: " + formatter.formatCoinWithCode(disputeResult.getBuyerPayoutAmount()) +
|
||||
"\nPayout amount for BTC seller: " + formatter.formatCoinWithCode(disputeResult.getSellerPayoutAmount()) +
|
||||
"\nArbitrators dispute fee: " + formatter.formatCoinWithCode(disputeResult.getArbitratorPayoutAmount()) +
|
||||
"\nArbitrator's dispute fee: " + formatter.formatCoinWithCode(disputeResult.getArbitratorPayoutAmount()) +
|
||||
"\n\nSummary notes:\n" + disputeResult.summaryNotesProperty().get();
|
||||
|
||||
dispute.setIsClosed(true);
|
||||
|
@ -528,10 +658,12 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void applyPayoutAmounts(DisputeResult.DisputeFeePolicy feePayment, Toggle selectedTradeAmountToggle) {
|
||||
calculatePayoutAmounts(feePayment);
|
||||
if (selectedTradeAmountToggle != null) {
|
||||
applyPayoutAmountsToDisputeResult(selectedTradeAmountToggle);
|
||||
applyTradeAmountRadioButtonStates();
|
||||
if (selectedTradeAmountToggle != customRadioButton) {
|
||||
calculatePayoutAmounts(feePayment);
|
||||
if (selectedTradeAmountToggle != null) {
|
||||
applyPayoutAmountsToDisputeResult(selectedTradeAmountToggle);
|
||||
applyTradeAmountRadioButtonStates();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -558,6 +690,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
arbitratorPayoutAmount = refund;
|
||||
break;
|
||||
}
|
||||
|
||||
winnerPayoutAmount = contract.getTradeAmount().add(winnerRefund);
|
||||
loserPayoutAmount = loserRefund;
|
||||
stalematePayoutAmount = contract.getTradeAmount().divide(2L).add(winnerRefund);
|
||||
|
@ -568,31 +701,44 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
disputeResult.setBuyerPayoutAmount(winnerPayoutAmount);
|
||||
disputeResult.setSellerPayoutAmount(loserPayoutAmount);
|
||||
disputeResult.setWinner(DisputeResult.Winner.BUYER);
|
||||
|
||||
buyerPayoutAmountInputTextField.setText(formatter.formatCoin(winnerPayoutAmount));
|
||||
sellerPayoutAmountInputTextField.setText(formatter.formatCoin(loserPayoutAmount));
|
||||
} else if (selectedTradeAmountToggle == sellerIsWinnerRadioButton) {
|
||||
disputeResult.setBuyerPayoutAmount(loserPayoutAmount);
|
||||
disputeResult.setSellerPayoutAmount(winnerPayoutAmount);
|
||||
disputeResult.setWinner(DisputeResult.Winner.SELLER);
|
||||
|
||||
buyerPayoutAmountInputTextField.setText(formatter.formatCoin(loserPayoutAmount));
|
||||
sellerPayoutAmountInputTextField.setText(formatter.formatCoin(winnerPayoutAmount));
|
||||
} else if (selectedTradeAmountToggle == shareRadioButton) {
|
||||
disputeResult.setBuyerPayoutAmount(stalematePayoutAmount);
|
||||
disputeResult.setSellerPayoutAmount(stalematePayoutAmount);
|
||||
disputeResult.setWinner(DisputeResult.Winner.STALE_MATE);
|
||||
|
||||
buyerPayoutAmountInputTextField.setText(formatter.formatCoin(stalematePayoutAmount));
|
||||
sellerPayoutAmountInputTextField.setText(formatter.formatCoin(stalematePayoutAmount));
|
||||
}
|
||||
disputeResult.setArbitratorPayoutAmount(arbitratorPayoutAmount);
|
||||
if (disputeResult.getBuyerPayoutAmount() != null) {
|
||||
log.debug("buyerPayoutAmount " + disputeResult.getBuyerPayoutAmount().toFriendlyString());
|
||||
log.debug("sellerPayoutAmount " + disputeResult.getSellerPayoutAmount().toFriendlyString());
|
||||
log.debug("arbitratorPayoutAmount " + disputeResult.getArbitratorPayoutAmount().toFriendlyString());
|
||||
}
|
||||
arbitratorPayoutAmountInputTextField.setText(formatter.formatCoin(arbitratorPayoutAmount));
|
||||
}
|
||||
|
||||
private void applyTradeAmountRadioButtonStates() {
|
||||
if (disputeResult.getBuyerPayoutAmount() != null) {
|
||||
if (disputeResult.getBuyerPayoutAmount().equals(winnerPayoutAmount) && disputeResult.getSellerPayoutAmount().equals(loserPayoutAmount))
|
||||
buyerIsWinnerRadioButton.setSelected(true);
|
||||
else if (disputeResult.getSellerPayoutAmount().equals(winnerPayoutAmount) && disputeResult.getBuyerPayoutAmount().equals(loserPayoutAmount))
|
||||
sellerIsWinnerRadioButton.setSelected(true);
|
||||
else
|
||||
shareRadioButton.setSelected(true); // there might be a not perfect split if only the trade amount is split but fees are not split
|
||||
Coin buyerPayoutAmount = disputeResult.getBuyerPayoutAmount();
|
||||
Coin sellerPayoutAmount = disputeResult.getSellerPayoutAmount();
|
||||
|
||||
buyerPayoutAmountInputTextField.setText(formatter.formatCoin(buyerPayoutAmount));
|
||||
sellerPayoutAmountInputTextField.setText(formatter.formatCoin(sellerPayoutAmount));
|
||||
arbitratorPayoutAmountInputTextField.setText(formatter.formatCoin(disputeResult.getArbitratorPayoutAmount()));
|
||||
|
||||
if (buyerPayoutAmount.equals(winnerPayoutAmount) && sellerPayoutAmount.equals(loserPayoutAmount)) {
|
||||
buyerIsWinnerRadioButton.setSelected(true);
|
||||
} else if (sellerPayoutAmount.equals(winnerPayoutAmount) && buyerPayoutAmount.equals(loserPayoutAmount)) {
|
||||
sellerIsWinnerRadioButton.setSelected(true);
|
||||
} else if (sellerPayoutAmount.equals(buyerPayoutAmount)) {
|
||||
shareRadioButton.setSelected(true);
|
||||
} else {
|
||||
customRadioButton.setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static io.bitsquare.gui.util.FormBuilder.addLabelInputTextField;
|
||||
|
@ -113,7 +112,7 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
|||
InputTextField keyInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "Private key to unlock:", 10).second;
|
||||
InputTextField offerIdsInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "Filtered offers (comma sep.):").second;
|
||||
InputTextField nodesInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "Filtered onion addresses (comma sep.):").second;
|
||||
InputTextField paymentAccountFilterInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "Filtered payment account data:\nFormat: comma sep. list of [payment method id | data field | value]").second;
|
||||
InputTextField paymentAccountFilterInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "Filtered trading account data:\nFormat: comma sep. list of [payment method id | data field | value]").second;
|
||||
GridPane.setHalignment(paymentAccountFilterInputTextField, HPos.RIGHT);
|
||||
|
||||
final Filter filter = filterManager.getDevelopersFilter();
|
||||
|
@ -137,16 +136,16 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
|||
}
|
||||
sendButton = new Button("Add filter");
|
||||
sendButton.setOnAction(e -> {
|
||||
List<String> offerIds = new ArrayList<>();
|
||||
List<String> nodes = new ArrayList<>();
|
||||
List<PaymentAccountFilter> paymentAccountFilters = new ArrayList<>();
|
||||
ArrayList<String> offerIds = new ArrayList<>();
|
||||
ArrayList<String> nodes = new ArrayList<>();
|
||||
ArrayList<PaymentAccountFilter> paymentAccountFilters = new ArrayList<>();
|
||||
|
||||
if (!offerIdsInputTextField.getText().isEmpty())
|
||||
offerIds = Arrays.asList(offerIdsInputTextField.getText().replace(" ", "").replace(", ", ",").split(","));
|
||||
offerIds = new ArrayList<>(Arrays.asList(offerIdsInputTextField.getText().replace(" ", "").replace(", ", ",").split(",")));
|
||||
if (!nodesInputTextField.getText().isEmpty())
|
||||
nodes = Arrays.asList(nodesInputTextField.getText().replace(":9999", "").replace(".onion", "").replace(" ", "").replace(", ", ",").split(","));
|
||||
nodes = new ArrayList<>(Arrays.asList(nodesInputTextField.getText().replace(":9999", "").replace(".onion", "").replace(" ", "").replace(", ", ",").split(",")));
|
||||
if (!paymentAccountFilterInputTextField.getText().isEmpty())
|
||||
paymentAccountFilters = Arrays.asList(paymentAccountFilterInputTextField.getText().replace(", ", ",").split(","))
|
||||
paymentAccountFilters = new ArrayList<>(Arrays.asList(paymentAccountFilterInputTextField.getText().replace(", ", ",").split(","))
|
||||
.stream().map(item -> {
|
||||
String[] list = item.split("\\|");
|
||||
if (list.length == 3)
|
||||
|
@ -154,7 +153,7 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
|||
else
|
||||
return new PaymentAccountFilter("", "", "");
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
if (sendFilterMessageHandler.handle(new Filter(offerIds, nodes, paymentAccountFilters), keyInputTextField.getText()))
|
||||
hide();
|
||||
|
|
|
@ -208,14 +208,14 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
|||
final boolean isNationalBanks = paymentMethod.equals(PaymentMethod.NATIONAL_BANK);
|
||||
final boolean isSepa = paymentMethod.equals(PaymentMethod.SEPA);
|
||||
if (offer.isMyOffer(keyRing) && offererPaymentAccountId != null && paymentAccount != null) {
|
||||
addLabelTextField(gridPane, ++rowIndex, "Payment account:", paymentAccount.getAccountName());
|
||||
addLabelTextField(gridPane, ++rowIndex, "My trading account:", paymentAccount.getAccountName());
|
||||
} else {
|
||||
final String method = BSResources.get(paymentMethod.getId());
|
||||
if (isNationalBanks || isSpecificBanks || isSepa) {
|
||||
if (BankUtil.isBankIdRequired(offer.getCountryCode()))
|
||||
addLabelTextField(gridPane, ++rowIndex, "Payment method (offerers bank ID):", method + bankId);
|
||||
addLabelTextField(gridPane, ++rowIndex, "Payment method (offerer's bank ID):", method + bankId);
|
||||
else if (BankUtil.isBankNameRequired(offer.getCountryCode()))
|
||||
addLabelTextField(gridPane, ++rowIndex, "Payment method (offerers bank name):", method + bankId);
|
||||
addLabelTextField(gridPane, ++rowIndex, "Payment method (offerer's bank name):", method + bankId);
|
||||
} else {
|
||||
addLabelTextField(gridPane, ++rowIndex, "Payment method:", method);
|
||||
}
|
||||
|
@ -262,12 +262,12 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
|||
|
||||
addTitledGroupBg(gridPane, ++rowIndex, rows, "Details", Layout.GROUP_DISTANCE);
|
||||
addLabelTextFieldWithCopyIcon(gridPane, rowIndex, "Offer ID:", offer.getId(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "Offerers onion address:", offer.getOffererNodeAddress().getFullAddress());
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "Offerer's onion address:", offer.getOffererNodeAddress().getFullAddress());
|
||||
addLabelTextField(gridPane, ++rowIndex, "Creation date:", formatter.formatDateTime(offer.getDate()));
|
||||
addLabelTextField(gridPane, ++rowIndex, "Security deposit:", formatter.formatCoinWithCode(FeePolicy.getSecurityDeposit()));
|
||||
|
||||
if (paymentMethodCountryCode != null)
|
||||
addLabelTextField(gridPane, ++rowIndex, "Offerers country of bank:",
|
||||
addLabelTextField(gridPane, ++rowIndex, "Offerer's country of bank:",
|
||||
CountryUtil.getNameAndCode(paymentMethodCountryCode));
|
||||
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "Accepted arbitrators:", formatter.arbitratorAddressesToString(offer.getArbitratorNodeAddresses()));
|
||||
|
@ -297,8 +297,8 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
|||
boolean isBuyOffer = offer.getDirection() == Offer.Direction.BUY;
|
||||
boolean isBuyerRole = isPlaceOffer ? isBuyOffer : !isBuyOffer;
|
||||
|
||||
String placeOfferButtonText = isBuyerRole ? "Confirm offer for buying bitcoin" : "Confirm offer for selling bitcoin";
|
||||
String takeOfferButtonText = isBuyerRole ? "Confirm offer for buying bitcoin" : "Confirm offer for selling bitcoin";
|
||||
String placeOfferButtonText = isBuyerRole ? "Confirm offer to buy bitcoin" : "Confirm offer to sell bitcoin";
|
||||
String takeOfferButtonText = isBuyerRole ? "Confirm offer to buy bitcoin" : "Confirm offer to sell bitcoin";
|
||||
|
||||
ImageView iconView = new ImageView();
|
||||
iconView.setId(isBuyerRole ? "image-buy-white" : "image-sell-white");
|
||||
|
|
|
@ -112,7 +112,7 @@ public class SendAlertMessageWindow extends Overlay<SendAlertMessageWindow> {
|
|||
CheckBox isUpdateCheckBox = addLabelCheckBox(gridPane, ++rowIndex, "Is update notification:", "").second;
|
||||
isUpdateCheckBox.setSelected(true);
|
||||
|
||||
InputTextField versionInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "New version nr.:").second;
|
||||
InputTextField versionInputTextField = addLabelInputTextField(gridPane, ++rowIndex, "New version no.:").second;
|
||||
versionInputTextField.disableProperty().bind(isUpdateCheckBox.selectedProperty().not());
|
||||
|
||||
sendButton = new Button("Send notification");
|
||||
|
|
|
@ -215,7 +215,7 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
log.error("wallet.getKeyCrypter() is null, than must not happen.");
|
||||
log.error("wallet.getKeyCrypter() is null, that must not happen.");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
<TableColumn text="Amount in BTC" fx:id="amountColumn" minWidth="130"/>
|
||||
<TableColumn text="Amount" fx:id="volumeColumn" minWidth="130"/>
|
||||
<TableColumn text="Trade type" fx:id="directionColumn" minWidth="80"/>
|
||||
<TableColumn text="State" fx:id="stateColumn" minWidth="80"/>
|
||||
<TableColumn text="Status" fx:id="stateColumn" minWidth="80"/>
|
||||
<TableColumn text="" fx:id="avatarColumn" minWidth="40" maxWidth="40"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
|
|
|
@ -29,10 +29,10 @@
|
|||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn text="Offer ID" fx:id="offerIdColumn" minWidth="120" maxWidth="130"/>
|
||||
<TableColumn text="Date/Time" fx:id="dateColumn" minWidth="170" maxWidth="190"/>
|
||||
<TableColumn text="Date/Time" fx:id="dateColumn" minWidth="180" maxWidth="190"/>
|
||||
<TableColumn text="Market" fx:id="marketColumn" minWidth="100"/>
|
||||
<TableColumn text="Price" fx:id="priceColumn" minWidth="160"/>
|
||||
<TableColumn text="Amount in BTC (min - max)" fx:id="amountColumn" minWidth="220"/>
|
||||
<TableColumn text="BTC (min - max)" fx:id="amountColumn" minWidth="160"/>
|
||||
<TableColumn text="Amount (min - max)" fx:id="volumeColumn" minWidth="180"/>
|
||||
<TableColumn text="Trade type" fx:id="directionColumn" minWidth="100"/>
|
||||
<TableColumn text="" fx:id="removeItemColumn" minWidth="120" maxWidth="120" sortable="false"/>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package io.bitsquare.gui.main.portfolio.openoffer;
|
||||
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.gui.Navigation;
|
||||
import io.bitsquare.gui.common.view.ActivatableViewAndModel;
|
||||
import io.bitsquare.gui.common.view.FxmlView;
|
||||
|
@ -111,7 +112,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
String key = "RemoveOfferWarning";
|
||||
if (preferences.showAgain(key))
|
||||
new Popup().warning("Are you sure you want to remove that offer?\n" +
|
||||
"The offer fee you have paid will be lost if you remove that offer.")
|
||||
"The offer fee of " + model.formatter.formatCoinWithCode(FeePolicy.getCreateOfferFee()) + " will be lost if you remove that offer.")
|
||||
.actionButtonText("Remove offer")
|
||||
.onAction(() -> doRemoveOpenOffer(openOffer))
|
||||
.closeButtonText("Don't remove the offer")
|
||||
|
|
|
@ -31,18 +31,17 @@ import org.bitcoinj.utils.Fiat;
|
|||
|
||||
class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel> implements ViewModel {
|
||||
private final P2PService p2PService;
|
||||
private final BSFormatter formatter;
|
||||
final BSFormatter formatter;
|
||||
|
||||
|
||||
@Inject
|
||||
public OpenOffersViewModel(OpenOffersDataModel dataModel, P2PService p2PService, BSFormatter formatter) {
|
||||
super(dataModel);
|
||||
this.p2PService = p2PService;
|
||||
|
||||
this.p2PService = p2PService;
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
|
||||
void onCancelOpenOffer(OpenOffer openOffer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||
dataModel.onCancelOpenOffer(openOffer, resultHandler, errorMessageHandler);
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ public class BuyerStep2View extends TradeStepView {
|
|||
"Please transfer from your external " +
|
||||
CurrencyUtil.getNameByCode(trade.getOffer().getCurrencyCode()) + " wallet\n" +
|
||||
model.formatter.formatVolumeWithCode(trade.getTradeVolume()) + " to the BTC seller.\n\n" +
|
||||
"Here are the payment account details of the bitcoin seller:\n" +
|
||||
"Here are the trading account details of the bitcoin seller:\n" +
|
||||
"" + paymentAccountContractData.getPaymentDetailsForTradePopup() + ".\n\n" +
|
||||
"(You can copy & paste the values from the main screen after closing that popup.)";
|
||||
else if (paymentAccountContractData != null)
|
||||
|
@ -80,7 +80,7 @@ public class BuyerStep2View extends TradeStepView {
|
|||
"(You can wait for more confirmations if you want - 6 confirmations are considered as very secure.)\n\n" +
|
||||
"Please go to a bank and pay " +
|
||||
model.formatter.formatVolumeWithCode(trade.getTradeVolume()) + " to the BTC seller.\n\n" +
|
||||
"Here are the payment account details of the BTC seller:\n" +
|
||||
"Here are the trading account details of the BTC seller:\n" +
|
||||
"" + paymentAccountContractData.getPaymentDetailsForTradePopup() + ".\n" +
|
||||
"(You can copy & paste the values from the main screen after closing that popup.)\n\n" +
|
||||
"Please don't forget to add the trade ID \"" + trade.getShortId() +
|
||||
|
@ -96,7 +96,7 @@ public class BuyerStep2View extends TradeStepView {
|
|||
"(You can wait for more confirmations if you want - 6 confirmations are considered as very secure.)\n\n" +
|
||||
"Please send " +
|
||||
model.formatter.formatVolumeWithCode(trade.getTradeVolume()) + " by \"US Postal Money Order\" to the BTC seller.\n\n" +
|
||||
"Here are the payment account details of the BTC seller:\n" +
|
||||
"Here are the trading account details of the BTC seller:\n" +
|
||||
"" + paymentAccountContractData.getPaymentDetailsForTradePopup() + ".\n" +
|
||||
"(You can copy & paste the values from the main screen after closing that popup.)\n\n" +
|
||||
"Please don't forget to add the trade ID \"" + trade.getShortId() +
|
||||
|
@ -108,7 +108,7 @@ public class BuyerStep2View extends TradeStepView {
|
|||
"(You can wait for more confirmations if you want - 6 confirmations are considered as very secure.)\n\n" +
|
||||
"Please go to your online banking web page and pay " +
|
||||
model.formatter.formatVolumeWithCode(trade.getTradeVolume()) + " to the BTC seller.\n\n" +
|
||||
"Here are the payment account details of the BTC seller:\n" +
|
||||
"Here are the trading account details of the BTC seller:\n" +
|
||||
"" + paymentAccountContractData.getPaymentDetailsForTradePopup() + ".\n" +
|
||||
"(You can copy & paste the values from the main screen after closing that popup.)\n\n" +
|
||||
"Please don't forget to add the trade ID \"" + trade.getShortId() +
|
||||
|
|
|
@ -170,8 +170,8 @@ public class SellerStep3View extends TradeStepView {
|
|||
} else {
|
||||
myPaymentDetails = myPaymentAccountContractData.getPaymentDetails();
|
||||
peersPaymentDetails = peersPaymentAccountContractData.getPaymentDetails();
|
||||
myTitle = "Your payment account:";
|
||||
peersTitle = "Buyers payment account:";
|
||||
myTitle = "Your trading account:";
|
||||
peersTitle = "Buyers trading account:";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,7 +211,7 @@ public class SellerStep3View extends TradeStepView {
|
|||
"confirm the payment when you have sufficient blockchain confirmations.";
|
||||
} else {
|
||||
return "The BTC buyer has started the " + model.dataModel.getCurrencyCode() + " payment.\n" +
|
||||
"Check at your payment account (e.g. bank account) and confirm when you have " +
|
||||
"Check at your trading account (e.g. bank account) and confirm when you have " +
|
||||
"received the payment.";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,8 @@ public class AboutView extends ActivatableViewAndModel<GridPane, Activatable> {
|
|||
|
||||
titledGroupBg = addTitledGroupBg(root, ++gridRow, 3, "Support Bitsquare", Layout.GROUP_DISTANCE);
|
||||
GridPane.setColumnSpan(titledGroupBg, 2);
|
||||
label = addLabel(root, gridRow, "Bitsquare is not a company but a community project and open for participation. If you want to participate or support Bitsquare please follow the links below.", Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
label = addLabel(root, gridRow, "Bitsquare is not a company but a community project and open for participation.\n" +
|
||||
"If you want to participate or support Bitsquare please follow the links below.", Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
label.setWrapText(true);
|
||||
GridPane.setColumnSpan(label, 2);
|
||||
GridPane.setHalignment(label, HPos.LEFT);
|
||||
|
|
|
@ -343,8 +343,8 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Activatab
|
|||
showOwnOffersInOfferBook = addLabelCheckBox(root, gridRow, "Show my own offers in offer book:", "", Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
||||
useAnimationsCheckBox = addLabelCheckBox(root, ++gridRow, "Use animations:", "").second;
|
||||
// useStickyMarketPriceCheckBox = addLabelCheckBox(root, ++gridRow, "Use sticky market price:", "").second;
|
||||
sortMarketCurrenciesNumericallyCheckBox = addLabelCheckBox(root, ++gridRow, "Sort market lists with nr. of offers/trades:", "").second;
|
||||
resetDontShowAgainButton = addLabelButton(root, ++gridRow, "Reset all don't show again flags:", "Reset", 0).second;
|
||||
sortMarketCurrenciesNumericallyCheckBox = addLabelCheckBox(root, ++gridRow, "Sort market lists with no. of offers/trades:", "").second;
|
||||
resetDontShowAgainButton = addLabelButton(root, ++gridRow, "Reset all 'Don't show again' flags:", "Reset", 0).second;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -557,11 +557,11 @@ public class BSFormatter {
|
|||
|
||||
public String getOfferDirectionForCreateOffer(Offer.Direction direction, String currencyCode) {
|
||||
if (CurrencyUtil.isFiatCurrency(currencyCode))
|
||||
return direction == Offer.Direction.BUY ? "You are creating an offer for buying BTC" :
|
||||
"You are creating an offer for selling BTC";
|
||||
return direction == Offer.Direction.BUY ? "You are creating an offer to buy BTC" :
|
||||
"You are creating an offer to sell BTC";
|
||||
else
|
||||
return direction == Offer.Direction.SELL ? "You are creating an offer for buying " + currencyCode + " (selling BTC)" :
|
||||
"You are creating an offer for selling " + currencyCode + " (buying BTC)";
|
||||
return direction == Offer.Direction.SELL ? "You are creating an offer to buy " + currencyCode + " (selling BTC)" :
|
||||
"You are creating an offer to sell " + currencyCode + " (buying BTC)";
|
||||
}
|
||||
|
||||
public String getRole(boolean isBuyerOffererAndSellerTaker, boolean isOfferer, String currencyCode) {
|
||||
|
|
|
@ -96,9 +96,9 @@ public class GUIUtil {
|
|||
Storage<ArrayList<PaymentAccount>> paymentAccountsStorage = new Storage<>(new File(directory));
|
||||
paymentAccountsStorage.initAndGetPersisted(accounts, fileName);
|
||||
paymentAccountsStorage.queueUpForSave();
|
||||
new Popup<>().feedback("Payment accounts saved to path:\n" + Paths.get(directory, fileName).toAbsolutePath()).show();
|
||||
new Popup<>().feedback("Trading accounts saved to path:\n" + Paths.get(directory, fileName).toAbsolutePath()).show();
|
||||
} else {
|
||||
new Popup<>().warning("You don't have payment accounts set up for exporting.").show();
|
||||
new Popup<>().warning("You don't have trading accounts set up for exporting.").show();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,15 +120,15 @@ public class GUIUtil {
|
|||
final String id = paymentAccount.getId();
|
||||
if (user.getPaymentAccount(id) == null) {
|
||||
user.addPaymentAccount(paymentAccount);
|
||||
msg.append("Payment account with id ").append(id).append("\n");
|
||||
msg.append("Trading account with id ").append(id).append("\n");
|
||||
} else {
|
||||
msg.append("We did not import payment account with id ").append(id).append(" because it exists already.\n");
|
||||
msg.append("We did not import trading account with id ").append(id).append(" because it exists already.\n");
|
||||
}
|
||||
});
|
||||
new Popup<>().feedback("Payment account imported from path:\n" + path + "\n\nImported accounts:\n" + msg).show();
|
||||
new Popup<>().feedback("Trading account imported from path:\n" + path + "\n\nImported accounts:\n" + msg).show();
|
||||
|
||||
} else {
|
||||
new Popup<>().warning("No exported payment accounts has been found at path: " + path + ".\n" + "File name is " + fileName + ".").show();
|
||||
new Popup<>().warning("No exported trading accounts has been found at path: " + path + ".\n" + "File name is " + fileName + ".").show();
|
||||
}
|
||||
} else {
|
||||
new Popup<>().warning("The selected file is not the expected file for import. The expected file name is: " + fileName + ".").show();
|
||||
|
@ -209,6 +209,32 @@ public class GUIUtil {
|
|||
};
|
||||
}
|
||||
|
||||
public static StringConverter<TradeCurrency> getTradeCurrencyConverter() {
|
||||
return new StringConverter<TradeCurrency>() {
|
||||
@Override
|
||||
public String toString(TradeCurrency tradeCurrency) {
|
||||
String code = tradeCurrency.getCode();
|
||||
final String displayString = CurrencyUtil.getNameAndCode(code);
|
||||
// http://boschista.deviantart.com/journal/Cool-ASCII-Symbols-214218618
|
||||
if (code.equals(GUIUtil.SHOW_ALL_FLAG))
|
||||
return "▶ Show all";
|
||||
else if (code.equals(GUIUtil.EDIT_FLAG))
|
||||
return "▼ Edit currency list";
|
||||
else if (tradeCurrency instanceof FiatCurrency)
|
||||
return "★ " + displayString;
|
||||
else if (tradeCurrency instanceof CryptoCurrency) {
|
||||
return "✦ " + displayString;
|
||||
} else
|
||||
return "-";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TradeCurrency fromString(String s) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void fillCurrencyListItems(List<TradeCurrency> tradeCurrencyList, ObservableList<CurrencyListItem> currencyListItems, @Nullable CurrencyListItem showAllCurrencyListItem, Preferences preferences) {
|
||||
Set<TradeCurrency> tradeCurrencySet = new HashSet<>();
|
||||
Map<String, Integer> tradesPerCurrencyMap = new HashMap<>();
|
||||
|
|
|
@ -21,12 +21,12 @@ validation.empty=Empty input is not allowed.
|
|||
validation.NaN=Input is not a valid number.
|
||||
validation.zero=Input of 0 is not allowed.
|
||||
validation.negative=A negative value is not allowed.
|
||||
validation.fiat.toSmall=Input smaller as minimum possible amount is not allowed.
|
||||
validation.fiat.toLarge=Input larger as maximum possible amount is not allowed.
|
||||
validation.fiat.toSmall=Input smaller than minimum possible amount is not allowed.
|
||||
validation.fiat.toLarge=Input larger than maximum possible amount is not allowed.
|
||||
validation.btc.toSmall=Input results in a bitcoin value with a fraction of the smallest unit (Satoshi).
|
||||
validation.btc.toLarge=Input larger as maximum trading amount of {0} is not allowed.
|
||||
validation.btc.toLarge=Input larger than maximum trading amount of {0} is not allowed.
|
||||
validation.passwordTooShort=The password you entered is too short. It needs to have min. 8 characters.
|
||||
validation.passwordTooLong=The password you entered is too long. It cannot be longer as 50 characters.
|
||||
validation.passwordTooLong=The password you entered is too long. It cannot be longer than 50 characters.
|
||||
validation.sortCodeNumber={0} must consist of {1} numbers
|
||||
validation.sortCodeChars={0} must consist of {1} characters
|
||||
validation.bankIdNumber={0} must consist of {1} numbers
|
||||
|
@ -45,8 +45,8 @@ createOffer.amountPriceBox.priceDescriptionFiat=Fixed price per {0}
|
|||
createOffer.amountPriceBox.buy.volumeDescription=Amount in {0} to spend
|
||||
createOffer.amountPriceBox.sell.volumeDescription=Amount in {0} to receive
|
||||
createOffer.amountPriceBox.minAmountDescription=Minimum amount of bitcoin
|
||||
createOffer.amountPriceBox.buy.info=Define a price for which you want to buy bitcoin and either enter the amount or the trade volume. With the minimum amount you can attract more potential traders with giving them more flexibility. But note that there is no automatic creation of a new offer for the remaining amount in the case that a trader takes your offer with a lower amount as defined in the amount field. Your offer will be removed from the offerbook once a trader has taken your offer.
|
||||
createOffer.amountPriceBox.sell.info=Define a price for which you want to sell bitcoin and either enter the amount or the trade volume. With the minimum amount you can attract more potential traders with giving them more flexibility. But note that there is no automatic creation of a new offer for the remaining amount in the case that a trader takes your offer with a lower amount as defined in the amount field. Your offer will be removed from the offerbook once a trader has taken your offer.
|
||||
createOffer.amountPriceBox.buy.info=Define a price for which you want to buy bitcoin and either enter the amount or the trade volume. With the minimum amount you can attract more potential traders by giving them more flexibility. But note that there is no automatic creation of a new offer for the remaining amount in the case that a trader takes your offer with a lower amount as defined in the amount field. Your offer will be removed from the offerbook once a trader has taken your offer.
|
||||
createOffer.amountPriceBox.sell.info=Define a price for which you want to sell bitcoin and either enter the amount or the trade volume. With the minimum amount you can attract more potential traders by giving them more flexibility. But note that there is no automatic creation of a new offer for the remaining amount in the case that a trader takes your offer with a lower amount as defined in the amount field. Your offer will be removed from the offerbook once a trader has taken your offer.
|
||||
createOffer.amountPriceBox.next=Next step
|
||||
createOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=The amount you have entered exceeds the number of allowed decimal places.\nThe amount has been adjusted to 4 decimal places.
|
||||
createOffer.amountPriceBox.warning.invalidFiatDecimalPlaces=The amount you have entered exceeds the number of allowed decimal places.\nThe amount has been adjusted.
|
||||
|
@ -60,7 +60,7 @@ createOffer.fundsBox.totalsNeeded=Funds needed:
|
|||
createOffer.fundsBox.totalsNeeded.prompt=Will be calculated from the bitcoin amount entered above
|
||||
createOffer.fundsBox.address=Trade wallet address:
|
||||
createOffer.fundsBox.balance=Trade wallet balance:
|
||||
createOffer.fundsBox.info=For every offer there is a dedicated trade wallet. You need to fund that trade wallet with the necessary bitcoin amount. Those funds are reserved and will be used in the case that your offer gets executed. If you cancel your offer you can withdraw your funds from that trading wallet. The only payment which will be done now when placing the offer is the offer fee payment.
|
||||
createOffer.fundsBox.info=For every offer there is a dedicated trade wallet. You need to fund that trade wallet with the necessary bitcoin amount. Those funds are reserved and will be used in the case that your offer gets executed. If you cancel your offer you can withdraw your funds from that trading wallet. The only payment made when placing an offer is the offer fee payment. https://bitsquare.io/faq/#6
|
||||
createOffer.fundsBox.tradeAmount=Trade amount:
|
||||
createOffer.fundsBox.securityDeposit=Security deposit:
|
||||
createOffer.fundsBox.offerFee=Create offer fee:
|
||||
|
@ -107,7 +107,7 @@ takeOffer.amountPriceBox.next=Next step
|
|||
takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=The amount you have entered exceeds the number of allowed decimal places.\nThe amount has been adjusted to 4 decimal places.
|
||||
takeOffer.validation.amountSmallerThanMinAmount=Amount cannot be smaller than minimum amount defined in the offer.
|
||||
takeOffer.validation.amountLargerThanOfferAmount=Input amount cannot be higher than the amount defined in the offer.
|
||||
takeOffer.validation.amountLargerThanOfferAmountMinusFee=That input amount would create a dust change for the BTC seller.
|
||||
takeOffer.validation.amountLargerThanOfferAmountMinusFee=That input amount would create dust change for the BTC seller.
|
||||
|
||||
takeOffer.fundsBox.title=Fund your trade
|
||||
takeOffer.fundsBox.isOfferAvailable=Check if offer is available...
|
||||
|
@ -115,11 +115,11 @@ takeOffer.fundsBox.totalsNeeded=Funds needed:
|
|||
takeOffer.fundsBox.totalsNeeded.prompt=Will be calculated from the bitcoin amount entered above
|
||||
takeOffer.fundsBox.address=Trade wallet address:
|
||||
takeOffer.fundsBox.balance=Trade wallet balance:
|
||||
takeOffer.fundsBox.buy.info=For every offer there is a dedicated trade wallet. You need to fund that trade wallet with the necessary bitcoin amount. Those \
|
||||
funds will be paid in to a locked deposit address. At the end of a successful trade you will get back your security deposit and the bitcoin amount you sold will be transferred to the \
|
||||
BTC buyer.
|
||||
takeOffer.fundsBox.sell.info=For every offer there is a dedicated trade wallet. You need to fund that trade wallet with the necessary bitcoin amount. Those \
|
||||
funds will be paid in to a locked deposit address. At the end of a successful trade you will get back your security deposit.
|
||||
takeOffer.fundsBox.buy.info=For every offer there is a dedicated trade wallet. You need to fund that trade wallet with the necessary bitcoin amount. \
|
||||
Those funds will be paid in to a locked deposit address. At the end of a successful trade you will get back your security deposit and the bitcoin amount you sold will be transferred \
|
||||
to the BTC buyer.
|
||||
takeOffer.fundsBox.sell.info=For every offer there is a dedicated trade wallet. You need to fund that trade wallet with the necessary bitcoin amount. \
|
||||
Those funds will be paid into a locked deposit address. At the end of a successful trade you will get back your security deposit.
|
||||
takeOffer.fundsBox.tradeAmount=Amount to sell:
|
||||
takeOffer.fundsBox.securityDeposit=Security deposit:
|
||||
takeOffer.fundsBox.offerFee=Take offer fee:
|
||||
|
@ -138,8 +138,8 @@ takeOffer.advancedBox.arbitrators=Accepted arbitrators:
|
|||
takeOffer.advancedBox.txType=Payments method:
|
||||
takeOffer.advancedBox.currency=Currency:
|
||||
takeOffer.advancedBox.county=Payments account country:
|
||||
takeOffer.advancedBox.info=These are the offer restrictions your trading partner has defined in his offer. Your \
|
||||
settings are matching those constraints and you are able to trade with him.
|
||||
takeOffer.advancedBox.info=These are the offer restrictions your trading partner has defined in his offer. \
|
||||
Your settings match those constraints and you are able to trade with him.
|
||||
|
||||
takeOffer.success.headline=You have successfully taken an offer
|
||||
takeOffer.success.info=You can see the status of your trade at the \"Portfolio\" screen under \"Open trades\".
|
||||
|
|
|
@ -35,6 +35,7 @@ public abstract class Connection implements Closeable {
|
|||
private final AtomicBoolean heartBeating;
|
||||
|
||||
public Connection(String peer, Socket socket) throws IOException {
|
||||
// LookAheadObjectInputStream not needed here as the class it not used in Bitsquare (used to test the library)
|
||||
this(peer, socket, Node.prepareOOSForSocket(socket), new ObjectInputStream(socket.getInputStream()));
|
||||
}
|
||||
|
||||
|
|
|
@ -235,6 +235,7 @@ public class Node {
|
|||
// get incoming data
|
||||
try {
|
||||
out = prepareOOSForSocket(socket);
|
||||
// LookAheadObjectInputStream not needed here as the class it not used in Bitsquare (used to test the library)
|
||||
objectInputStream = new ObjectInputStream(socket.getInputStream());
|
||||
} catch (EOFException e) {
|
||||
log.debug("Got bogus incoming connection");
|
||||
|
|
|
@ -668,7 +668,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||
// does not arrive.
|
||||
// We could use onBroadcastCompleted instead but it might take too long if one peer
|
||||
// is very badly connected.
|
||||
// TODO We could check for a certain threshold of nr. of incoming messages of the same msg
|
||||
// TODO We could check for a certain threshold of no. of incoming messages of the same msg
|
||||
// to see how well it is propagated. BitcoinJ uses such an approach for tx propagation.
|
||||
UserThread.runAfter(() -> {
|
||||
log.info("Broadcasted to first peer (with 3 sec. delayed): Message = {}", Utilities.toTruncatedString(message));
|
||||
|
|
|
@ -69,7 +69,7 @@ public class Utils {
|
|||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public static Serializable decompress(byte[] compressedData) {
|
||||
public static Serializable decompress(byte[] compressedData) throws IOException, ClassNotFoundException {
|
||||
return (Serializable) ByteArrayUtils.byteArrayToObject(decompress(compressedData, compressedData.length));
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,8 @@ public enum CloseConnectionReason {
|
|||
|
||||
// illegal requests
|
||||
RULE_VIOLATION(true, false),
|
||||
PEER_BANNED(true, false);
|
||||
PEER_BANNED(true, false),
|
||||
INVALID_CLASS_RECEIVED(false, false);
|
||||
|
||||
public final boolean sendCloseMessage;
|
||||
public boolean isIntended;
|
||||
|
|
|
@ -9,6 +9,7 @@ import io.bitsquare.common.ByteArrayUtils;
|
|||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.util.Tuple2;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.io.LookAheadObjectInputStream;
|
||||
import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.p2p.messaging.PrefixedSealedAndSignedMessage;
|
||||
|
@ -146,24 +147,24 @@ public class Connection implements MessageListener {
|
|||
// the associated ObjectOutputStream on the other end of the connection has written.
|
||||
// It will not return until that header has been read.
|
||||
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
|
||||
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
|
||||
|
||||
ObjectInputStream objectInputStream = new LookAheadObjectInputStream(socket.getInputStream(), true);
|
||||
// We create a thread for handling inputStream data
|
||||
inputHandler = new InputHandler(sharedModel, objectInputStream, portInfo, this);
|
||||
singleThreadExecutor.submit(inputHandler);
|
||||
} catch (IOException e) {
|
||||
|
||||
// Use Peer as default, in case of other types they will set it as soon as possible.
|
||||
peerType = PeerType.PEER;
|
||||
|
||||
if (peersNodeAddress != null)
|
||||
setPeersNodeAddress(peersNodeAddress);
|
||||
|
||||
log.trace("New connection created: " + this.toString());
|
||||
|
||||
UserThread.execute(() -> connectionListener.onConnection(this));
|
||||
|
||||
} catch (Throwable e) {
|
||||
sharedModel.handleConnectionException(e);
|
||||
}
|
||||
|
||||
// Use Peer as default, in case of other types they will set it as soon as possible.
|
||||
peerType = PeerType.PEER;
|
||||
|
||||
if (peersNodeAddress != null)
|
||||
setPeersNodeAddress(peersNodeAddress);
|
||||
|
||||
log.trace("New connection created: " + this.toString());
|
||||
|
||||
UserThread.execute(() -> connectionListener.onConnection(this));
|
||||
}
|
||||
|
||||
|
||||
|
@ -590,6 +591,8 @@ public class Connection implements MessageListener {
|
|||
if (ruleViolation == RuleViolation.PEER_BANNED) {
|
||||
log.warn("We detected a connection to a banned peer. We will close that connection. (reportInvalidRequest)");
|
||||
shutDown(CloseConnectionReason.PEER_BANNED);
|
||||
} else if (ruleViolation == RuleViolation.INVALID_CLASS) {
|
||||
shutDown(CloseConnectionReason.INVALID_CLASS_RECEIVED);
|
||||
} else {
|
||||
shutDown(CloseConnectionReason.RULE_VIOLATION);
|
||||
}
|
||||
|
@ -888,6 +891,11 @@ public class Connection implements MessageListener {
|
|||
|
||||
messageListener.onMessage(message, connection);
|
||||
}
|
||||
} catch (InvalidClassException e) {
|
||||
log.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
reportInvalidRequest(RuleViolation.INVALID_CLASS);
|
||||
return;
|
||||
} catch (ClassNotFoundException | NoClassDefFoundError e) {
|
||||
log.warn(e.getMessage());
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -6,7 +6,8 @@ public enum RuleViolation {
|
|||
MAX_MSG_SIZE_EXCEEDED(2),
|
||||
THROTTLE_LIMIT_EXCEEDED(2),
|
||||
TOO_MANY_REPORTED_PEERS_SENT(2),
|
||||
PEER_BANNED(0);
|
||||
PEER_BANNED(0),
|
||||
INVALID_CLASS(0);
|
||||
|
||||
public final int maxTolerance;
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ public class PeerManager implements ConnectionListener {
|
|||
public void onConnection(Connection connection) {
|
||||
Log.logIfStressTests("onConnection to peer " +
|
||||
(connection.getPeersNodeAddressOptional().isPresent() ? connection.getPeersNodeAddressOptional().get() : "PeersNode unknown") +
|
||||
" / Nr. of connections: " + networkNode.getAllConnections().size());
|
||||
" / No. of connections: " + networkNode.getAllConnections().size());
|
||||
|
||||
final boolean seedNode = isSeedNode(connection);
|
||||
|
||||
|
@ -182,7 +182,7 @@ public class PeerManager implements ConnectionListener {
|
|||
public void onDisconnect(CloseConnectionReason closeConnectionReason, Connection connection) {
|
||||
Log.logIfStressTests("onDisconnect of peer " +
|
||||
(connection.getPeersNodeAddressOptional().isPresent() ? connection.getPeersNodeAddressOptional().get() : "PeersNode unknown") +
|
||||
" / Nr. of connections: " + networkNode.getAllConnections().size() +
|
||||
" / No. of connections: " + networkNode.getAllConnections().size() +
|
||||
" / closeConnectionReason: " + closeConnectionReason);
|
||||
|
||||
final Optional<NodeAddress> addressOptional = connection.getPeersNodeAddressOptional();
|
||||
|
|
|
@ -16,7 +16,7 @@ import java.security.spec.X509EncodedKeySpec;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Envelope message which support a time to live and sender and receivers pub keys for storage operations.
|
||||
* Envelope message which support a time to live and sender and receiver's pub keys for storage operations.
|
||||
* It differs from the ProtectedExpirableMessage in the way that the sender is permitted to do an add operation
|
||||
* but only the receiver is permitted to remove the data.
|
||||
* That is the typical requirement for a mailbox like system.
|
||||
|
|
|
@ -58,13 +58,13 @@ public class DummySeedNode {
|
|||
// BitcoinNetworkId: The id for the bitcoin network (Mainnet = 0, TestNet = 1, Regtest = 2)
|
||||
// localhost:3002 2 50 true
|
||||
// localhost:3002 2 50 localhost:4442|localhost:4443 true
|
||||
// Usage: -myAddress=<my onion address> -networkId=<networkId (Mainnet = 0, TestNet = 1, Regtest = 2)> -maxConnections=<Nr. of max. connections allowed> -useLocalhost=false -seedNodes=si3uu56adkyqkldl.onion:8002|eo5ay2lyzrfvx2nr.onion:8002 -ignore=4543y2lyzrfvx2nr.onion:8002|876572lyzrfvx2nr.onion:8002
|
||||
// Usage: -myAddress=<my onion address> -networkId=<networkId (Mainnet = 0, TestNet = 1, Regtest = 2)> -maxConnections=<No. of max. connections allowed> -useLocalhost=false -seedNodes=si3uu56adkyqkldl.onion:8002|eo5ay2lyzrfvx2nr.onion:8002 -ignore=4543y2lyzrfvx2nr.onion:8002|876572lyzrfvx2nr.onion:8002
|
||||
// Example usage: -myAddress=lmvdenjkyvx2ovga.onion:8001 -networkId=0 -maxConnections=20 -useLocalhost=false -seedNodes=si3uu56adkyqkldl.onion:8002|eo5ay2lyzrfvx2nr.onion:8002 -ignore=4543y2lyzrfvx2nr.onion:8002|876572lyzrfvx2nr.onion:8002
|
||||
|
||||
public static final String USAGE = "Usage:\n" +
|
||||
"--myAddress=<my onion address>\n" +
|
||||
"--networkId=[0|1|2] (Mainnet = 0, TestNet = 1, Regtest = 2)\n" +
|
||||
"--maxConnections=<Nr. of max. connections allowed>\n" +
|
||||
"--maxConnections=<No. of max. connections allowed>\n" +
|
||||
"--useLocalhost=[true|false]\n" +
|
||||
"--logLevel=Log level [OFF, ALL, ERROR, WARN, INFO, DEBUG, TRACE]\n" +
|
||||
"--seedNodes=[onion addresses separated with comma]\n" +
|
||||
|
|
|
@ -451,8 +451,8 @@ public class PeerServiceTest {
|
|||
log.debug("total authentications " + authentications);
|
||||
Profiler.printSystemLoad(log);
|
||||
// total authentications at 8 nodes = 56
|
||||
// total authentications at com nodes = 90, System load (nr. threads/used memory (MB)): 170/20
|
||||
// total authentications at 20 nodes = 380, System load (nr. threads/used memory (MB)): 525/46
|
||||
// total authentications at com nodes = 90, System load (no. threads/used memory (MB)): 170/20
|
||||
// total authentications at 20 nodes = 380, System load (no. threads/used memory (MB)): 525/46
|
||||
for (int i = 0; i < length; i++) {
|
||||
nodes[i].getP2PService().getPeerGroup().printAuthenticatedPeers();
|
||||
nodes[i].getP2PService().getPeerGroup().printReportedPeers();
|
||||
|
|
|
@ -414,8 +414,8 @@ public class PeerManagerTest {
|
|||
log.debug("total authentications " + authentications);
|
||||
Profiler.printSystemLoad(log);
|
||||
// total authentications at 8 nodes = 56
|
||||
// total authentications at com nodes = 90, System load (nr. threads/used memory (MB)): 170/20
|
||||
// total authentications at 20 nodes = 380, System load (nr. threads/used memory (MB)): 525/46
|
||||
// total authentications at com nodes = 90, System load (no. threads/used memory (MB)): 170/20
|
||||
// total authentications at 20 nodes = 380, System load (no. threads/used memory (MB)): 525/46
|
||||
for (int i = 0; i < length; i++) {
|
||||
nodes[i].getP2PService().getPeerGroup().printAuthenticatedPeers();
|
||||
nodes[i].getP2PService().getPeerGroup().printReportedPeers();
|
||||
|
|
|
@ -33,13 +33,16 @@ cp "/Users/mk/vm_shared_windows/bundles/$exe" "/Users/mk/vm_shared_win10/$win64"
|
|||
|
||||
cd "$target_dir"
|
||||
|
||||
#shasum -a 256 "$mac" "$deb64" "$deb32" "$rpm64" "$rpm32" "$win64" "$win32" > sha256_hashes.txt
|
||||
shasum -a 256 "$mac" "$deb64" "$deb32" "$win64" "$win32" > sha256_hashes.txt
|
||||
gpg --digest-algo SHA256 --local-user manfred@bitsquare.io --output $mac.asc --detach-sig --armor $mac
|
||||
gpg --digest-algo SHA256 --local-user manfred@bitsquare.io --output $deb64.asc --detach-sig --armor $deb64
|
||||
gpg --digest-algo SHA256 --local-user manfred@bitsquare.io --output $deb32.asc --detach-sig --armor $deb32
|
||||
gpg --digest-algo SHA256 --local-user manfred@bitsquare.io --output $win64.asc --detach-sig --armor $win64
|
||||
gpg --digest-algo SHA256 --local-user manfred@bitsquare.io --output $win32.asc --detach-sig --armor $win32
|
||||
|
||||
gpg --digest-algo SHA256 --local-user manfred@bitsquare.io --output signed_sha256_hashes.txt --clearsign sha256_hashes.txt
|
||||
|
||||
gpg --digest-algo SHA256 --verify signed_sha256_hashes.txt
|
||||
|
||||
rm "$target_dir/sha256_hashes.txt"
|
||||
gpg --digest-algo SHA256 --verify $mac{.asc*,}
|
||||
gpg --digest-algo SHA256 --verify $deb64{.asc*,}
|
||||
gpg --digest-algo SHA256 --verify $deb32{.asc*,}
|
||||
gpg --digest-algo SHA256 --verify $win64{.asc*,}
|
||||
gpg --digest-algo SHA256 --verify $win32{.asc*,}
|
||||
|
||||
open "$target_dir"
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
:: Invoke from bitsquare home directory
|
||||
:: edit iss file -> AppVersion
|
||||
|
||||
:: Copy gui/deploy.Bitsquare.jar file from mac build to windows
|
||||
:: edit -> -BappVersion and -srcfiles
|
||||
|
||||
:: 64 bit build
|
||||
:: 32 bit build
|
||||
:: Needs Inno Setup 5 or later (http://www.jrsoftware.org/isdl.php)
|
||||
|
||||
SET version=0.4.9.6
|
||||
SET jdk=C:\Program Files\Java\jdk1.8.0_92
|
||||
SET outdir=\\VBOXSVR\vm_shared_windows_32bit
|
||||
|
||||
call "%jdk%\bin\javapackager.exe" -deploy ^
|
||||
:: Private setup
|
||||
SET outdir=\\VBOXSVR\vm_shared_windows_32bit
|
||||
:: Others might use the following
|
||||
:: SET outdir=.
|
||||
|
||||
copy gui\target\shaded.jar Bitsquare-%version%.jar
|
||||
call "%JAVA_HOME%\bin\javapackager.exe" -deploy ^
|
||||
-BappVersion="%version%" ^
|
||||
-native exe ^
|
||||
-name Bitsquare ^
|
||||
|
@ -20,5 +23,5 @@ call "%jdk%\bin\javapackager.exe" -deploy ^
|
|||
-appclass io.bitsquare.app.BitsquareAppMain ^
|
||||
-srcfiles %outdir%\Bitsquare-%version%.jar ^
|
||||
-outfile Bitsquare ^
|
||||
-Bruntime="%jdk%\jre" ^
|
||||
-Bruntime="%JAVA_HOME%\jre" ^
|
||||
-BjvmProperties=-Djava.net.preferIPv4Stack=true
|
|
@ -1,6 +1,5 @@
|
|||
:: Invoke from bitsquare home directory
|
||||
:: edit iss file -> AppVersion
|
||||
|
||||
:: Copy gui/deploy.Bitsquare.jar file from mac build to windows
|
||||
:: edit -> -BappVersion and -srcfiles
|
||||
|
||||
:: 64 bit build
|
||||
|
@ -9,10 +8,14 @@
|
|||
:: Did not get -BjvmOptions=-Xbootclasspath working on windows, but if the jdkfix jar is copied into the jdk/jre dir it will override the default classes
|
||||
|
||||
SET version=0.4.9.6
|
||||
SET jdk=C:\Program Files\Java\jdk1.8.0_92
|
||||
SET outdir=\\VBOXSVR\vm_shared_windows
|
||||
|
||||
call "%jdk%\bin\javapackager.exe" -deploy ^
|
||||
:: Private setup
|
||||
SET outdir=\\VBOXSVR\vm_shared_windows
|
||||
:: Others might use the following
|
||||
:: SET outdir=.
|
||||
|
||||
|
||||
call "%JAVA_HOME%\bin\javapackager.exe" -deploy ^
|
||||
-BappVersion="%version%" ^
|
||||
-native exe ^
|
||||
-name Bitsquare ^
|
||||
|
@ -22,5 +25,5 @@ call "%jdk%\bin\javapackager.exe" -deploy ^
|
|||
-appclass io.bitsquare.app.BitsquareAppMain ^
|
||||
-srcfiles %outdir%\Bitsquare-%version%.jar ^
|
||||
-outfile Bitsquare ^
|
||||
-Bruntime="%jdk%\jre" ^
|
||||
-Bruntime="%JAVA_HOME%\jre" ^
|
||||
-BjvmProperties=-Djava.net.preferIPv4Stack=true
|
5
pom.xml
5
pom.xml
|
@ -156,6 +156,11 @@
|
|||
<artifactId>lombok</artifactId>
|
||||
<version>1.16.10</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<version>3.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<!--logging-->
|
||||
<dependency>
|
||||
|
|
Loading…
Add table
Reference in a new issue