Add support for customized currency lists

This commit is contained in:
Manfred Karrer 2016-03-01 20:40:15 +01:00
parent 59ad7653b5
commit 2f0f58c478
33 changed files with 769 additions and 357 deletions

View File

@ -33,7 +33,7 @@ public class PoloniexPriceProvider implements PriceProvider {
String response = httpClient.requestWithGET("?command=returnTicker");
LinkedTreeMap<String, Object> treeMap = new Gson().fromJson(response, LinkedTreeMap.class);
Map<String, String> temp = new HashMap<>();
Set<String> supported = CurrencyUtil.getSortedCryptoCurrencies().stream()
Set<String> supported = CurrencyUtil.getAllSortedCryptoCurrencies().stream()
.map(TradeCurrency::getCode)
.collect(Collectors.toSet());
treeMap.entrySet().stream().forEach(e -> {

View File

@ -126,7 +126,7 @@ public class CountryUtil {
selectedRegion != null && country != null && selectedRegion.equals(country.region)));
}
private static List<Country> getAllCountries() {
public static List<Country> getAllCountries() {
final List<Country> allCountries = new ArrayList<>();
for (final Locale locale : getAllCountryLocales()) {
String regionCode = getRegionCode(locale.getCountry());

View File

@ -27,14 +27,96 @@ import java.util.stream.Collectors;
public class CurrencyUtil {
private static final Logger log = LoggerFactory.getLogger(CurrencyUtil.class);
private static final List<TradeCurrency> allSortedCurrencies = createAllSortedCurrenciesList();
private static final List<FiatCurrency> allSortedFiatCurrencies = createAllSortedFiatCurrenciesList();
public static List<TradeCurrency> getAllSortedCurrencies() {
return allSortedCurrencies;
private static List<FiatCurrency> createAllSortedFiatCurrenciesList() {
Set<FiatCurrency> set = CountryUtil.getAllCountries().stream()
.map(country -> getCurrencyByCountryCode(country.code))
.collect(Collectors.toSet());
List<FiatCurrency> list = new ArrayList<>(set);
list.sort(TradeCurrency::compareTo);
return list;
}
// We add all currencies supported by payment methods
private static List<TradeCurrency> createAllSortedCurrenciesList() {
public static List<FiatCurrency> getAllSortedFiatCurrencies() {
return allSortedFiatCurrencies;
}
public static List<FiatCurrency> getAllMainFiatCurrencies() {
List<FiatCurrency> list = new ArrayList<>();
// Top traded currencies
list.add(new FiatCurrency("USD"));
list.add(new FiatCurrency("EUR"));
list.add(new FiatCurrency("GBP"));
list.add(new FiatCurrency("CAD"));
list.add(new FiatCurrency("AUD"));
list.add(new FiatCurrency("RUB"));
list.add(new FiatCurrency("INR"));
TradeCurrency defaultTradeCurrency = getDefaultTradeCurrency();
FiatCurrency defaultFiatCurrency = defaultTradeCurrency instanceof FiatCurrency ? (FiatCurrency) defaultTradeCurrency : null;
if (defaultFiatCurrency != null && list.contains(defaultFiatCurrency)) {
list.remove(defaultTradeCurrency);
list.add(0, defaultFiatCurrency);
}
return list;
}
private static final List<CryptoCurrency> allSortedCryptoCurrencies = createAllSortedCryptoCurrenciesList();
public static List<CryptoCurrency> getAllSortedCryptoCurrencies() {
return allSortedCryptoCurrencies;
}
public static List<CryptoCurrency> getMainCryptoCurrencies() {
final List<CryptoCurrency> result = new ArrayList<>();
result.add(new CryptoCurrency("ETH", "Ethereum"));
result.add(new CryptoCurrency("LTC", "Litecoin"));
result.add(new CryptoCurrency("NMC", "Namecoin"));
result.add(new CryptoCurrency("DASH", "Dash"));
result.add(new CryptoCurrency("NBT", "NuBits"));
result.add(new CryptoCurrency("DOGE", "Dogecoin"));
result.add(new CryptoCurrency("NXT", "Nxt"));
result.add(new CryptoCurrency("BTS", "BitShares"));
return result;
}
public static List<CryptoCurrency> createAllSortedCryptoCurrenciesList() {
final List<CryptoCurrency> result = new ArrayList<>();
result.add(new CryptoCurrency("ETH", "Ethereum"));
result.add(new CryptoCurrency("LTC", "Litecoin"));
result.add(new CryptoCurrency("NMC", "Namecoin"));
result.add(new CryptoCurrency("DASH", "Dash"));
result.add(new CryptoCurrency("NBT", "NuBits"));
result.add(new CryptoCurrency("NSR", "NuShares"));
result.add(new CryptoCurrency("PPC", "Peercoin"));
result.add(new CryptoCurrency("XPM", "Primecoin"));
result.add(new CryptoCurrency("SC", "Siacoin"));
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("BTS", "BitShares"));
result.add(new CryptoCurrency("XCP", "Counterparty"));
result.add(new CryptoCurrency("XRP", "Ripple"));
// Unfortunately we cannot support CryptoNote coins yet as there is no way to proof the transaction. Payment ID helps only locate the tx but the
// arbitrator cannot see if the receiving key matches the receivers address. They might add support for exposing the tx key, but that is not
// implemented yet. To use the view key (also not available in GUI wallets) would reveal the complete wallet history for incoming payments, which is
// not acceptable from privacy point of view.
// result.add(new CryptoCurrency("XMR", "Monero"));
// result.add(new CryptoCurrency("BCN", "Bytecoin"));
return result;
}
/* // We add all currencies supported by payment methods
// TODO not used anymore
private static List<TradeCurrency> createAllSortedCurrenciesListDerivedFromPaymentMethods() {
Set<TradeCurrency> set = new HashSet<>();
// Sepa: EUR at first place
@ -52,11 +134,11 @@ public class CurrencyUtil {
// Swish: it is already added by SEPA
// for printing out all codes
/* String res;
*//* String res;
result.stream().forEach(e -> {
res += "list.add(new FiatCurrency(\""+e.code+"\"));\n";
});
log.debug(res);*/
log.debug(res);*//*
List<TradeCurrency> list = getAllManuallySortedFiatCurrencies();
@ -84,9 +166,10 @@ public class CurrencyUtil {
getSortedCryptoCurrencies().stream().forEach(list::add);
return list;
}
}*/
private static List<TradeCurrency> getAllManuallySortedFiatCurrencies() {
/* private static List<TradeCurrency> getAllManuallySortedFiatCurrencies() {
List<TradeCurrency> list = new ArrayList<>();
list.add(new FiatCurrency("EUR"));
list.add(new FiatCurrency("USD"));
@ -116,7 +199,7 @@ public class CurrencyUtil {
list.add(new FiatCurrency("RON"));
return list;
}
}*/
/**
* @return Sorted list of SEPA currencies with EUR as first item
@ -160,41 +243,11 @@ public class CurrencyUtil {
@SuppressWarnings("WeakerAccess")
public static boolean isCryptoCurrency(String currencyCode) {
return getSortedCryptoCurrencies().stream().filter(e -> e.getCode().equals(currencyCode)).findAny().isPresent();
return getAllSortedCryptoCurrencies().stream().filter(e -> e.getCode().equals(currencyCode)).findAny().isPresent();
}
public static Optional<TradeCurrency> getCryptoCurrency(String currencyCode) {
return getSortedCryptoCurrencies().stream().filter(e -> e.getCode().equals(currencyCode)).findAny();
}
public static List<TradeCurrency> getSortedCryptoCurrencies() {
final List<TradeCurrency> result = new ArrayList<>();
result.add(new CryptoCurrency("ETH", "Ethereum"));
result.add(new CryptoCurrency("LTC", "Litecoin"));
result.add(new CryptoCurrency("NMC", "Namecoin"));
result.add(new CryptoCurrency("DASH", "Dash"));
result.add(new CryptoCurrency("NBT", "NuBits"));
result.add(new CryptoCurrency("NSR", "NuShares"));
result.add(new CryptoCurrency("PPC", "Peercoin"));
result.add(new CryptoCurrency("XPM", "Primecoin"));
result.add(new CryptoCurrency("SC", "Siacoin"));
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("BTS", "BitShares"));
result.add(new CryptoCurrency("XCP", "Counterparty"));
result.add(new CryptoCurrency("XRP", "Ripple"));
// Unfortunately we cannot support CryptoNote coins yet as there is no way to proof the transaction. Payment ID helps only locate the tx but the
// arbitrator cannot see if the receiving key matches the receivers address. They might add support for exposing the tx key, but that is not
// implemented yet. To use the view key (also not available in GUI wallets) would reveal the complete wallet history for incoming payments, which is
// not acceptable from privacy point of view.
// result.add(new CryptoCurrency("XMR", "Monero"));
// result.add(new CryptoCurrency("BCN", "Bytecoin"));
return result;
public static Optional<CryptoCurrency> getCryptoCurrency(String currencyCode) {
return getAllSortedCryptoCurrencies().stream().filter(e -> e.getCode().equals(currencyCode)).findAny();
}
public static boolean isCryptoNoteCoin(String currencyCode) {
@ -206,6 +259,9 @@ public class CurrencyUtil {
if (!countryCode.equals("LT"))
return new FiatCurrency(Currency.getInstance(new Locale(LanguageUtil.getDefaultLanguage(), countryCode)).getCurrencyCode());
else {
if (!Currency.getInstance(new Locale(LanguageUtil.getDefaultLanguage(), countryCode)).getCurrencyCode().equals("EUR"))
log.error("wrong currency reported for LT");
return new FiatCurrency("EUR");
}
}
@ -216,7 +272,7 @@ public class CurrencyUtil {
return Currency.getInstance(currencyCode).getDisplayName(Preferences.getDefaultLocale());
} catch (Throwable t) {
// Seems that it is a cryptocurrency
return getSortedCryptoCurrencies().stream().filter(e -> e.getCode().equals(currencyCode)).findFirst().get().getName();
return getAllSortedCryptoCurrencies().stream().filter(e -> e.getCode().equals(currencyCode)).findFirst().get().getName();
}
}

View File

@ -19,8 +19,9 @@ package io.bitsquare.locale;
import io.bitsquare.app.Version;
import io.bitsquare.common.persistance.Persistable;
import org.jetbrains.annotations.NotNull;
public abstract class TradeCurrency implements Persistable {
public abstract class TradeCurrency implements Persistable, Comparable<TradeCurrency> {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
@ -65,6 +66,11 @@ public abstract class TradeCurrency implements Persistable {
return code + " (" + name + ")";
}
@Override
public int compareTo(@NotNull TradeCurrency other) {
return this.getName().compareTo(other.getName());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View File

@ -29,12 +29,12 @@ public abstract class BankAccountContractData extends PaymentAccountContractData
private static final Logger log = LoggerFactory.getLogger(BankAccountContractData.class);
private String holderName;
private String bankName;
private String bankId;
private String branchId;
private String accountNr;
private String holderId;
protected String holderName;
protected String bankName;
protected String bankId;
protected String branchId;
protected String accountNr;
protected String holderId;
public BankAccountContractData(String paymentMethod, String id, int maxTradePeriod) {
super(paymentMethod, id, maxTradePeriod);

View File

@ -31,4 +31,8 @@ public final class SameBankAccount extends PaymentAccount {
protected PaymentAccountContractData setContractData() {
return new SameBankAccountContractData(paymentMethod.getId(), id, paymentMethod.getMaxTradePeriod());
}
public String getAcceptedBank() {
return ((SameBankAccountContractData) contractData).getBankName();
}
}

View File

@ -19,6 +19,8 @@ package io.bitsquare.payment;
import io.bitsquare.app.Version;
import java.util.ArrayList;
public final class SpecificBankAccount extends PaymentAccount {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
@ -31,4 +33,8 @@ public final class SpecificBankAccount extends PaymentAccount {
protected PaymentAccountContractData setContractData() {
return new SpecificBanksAccountContractData(paymentMethod.getId(), id, paymentMethod.getMaxTradePeriod());
}
public ArrayList<String> getAcceptedBanks() {
return ((SpecificBanksAccountContractData) contractData).getAcceptedBanks();
}
}

View File

@ -17,7 +17,10 @@
package io.bitsquare.payment;
import com.google.common.base.Joiner;
import io.bitsquare.app.Version;
import io.bitsquare.locale.BankUtil;
import io.bitsquare.locale.CountryUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -56,4 +59,17 @@ public final class SpecificBanksAccountContractData extends BankAccountContractD
public String getPaymentDetails() {
return "Transfers with specific banks - " + getPaymentDetailsForTradePopup().replace("\n", ", ");
}
@Override
public String getPaymentDetailsForTradePopup() {
String holderIdString = BankUtil.requiresHolderId(countryCode) ? (getHolderIdLabel() + ": " + holderId + "\n") : "";
return "Holder name: " + holderName + "\n" +
holderIdString +
"Bank name: " + bankName + "\n" +
"Bank Nr.: " + bankId + "\n" +
"Branch Nr.: " + branchId + "\n" +
"Account Nr.: " + accountNr + "\n" +
"Accepted banks: " + Joiner.on(", ").join(acceptedBanks) + "\n" +
"Country of bank: " + CountryUtil.getNameAndCode(getCountryCode());
}
}

View File

@ -102,6 +102,8 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
@Nullable
private final ArrayList<String> acceptedCountryCodes;
@Nullable
private final ArrayList<String> acceptedBanks;
private final ArrayList<NodeAddress> arbitratorNodeAddresses;
// Mutable property. Has to be set before offer is save in P2P network as it changes the objects hash!
@ -136,7 +138,8 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
@Nullable Country paymentMethodCountry,
String offererPaymentAccountId,
ArrayList<NodeAddress> arbitratorNodeAddresses,
@Nullable ArrayList<String> acceptedCountryCodes) {
@Nullable ArrayList<String> acceptedCountryCodes,
@Nullable ArrayList<String> acceptedBanks) {
this.id = id;
this.offererNodeAddress = offererNodeAddress;
this.pubKeyRing = pubKeyRing;
@ -150,6 +153,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
this.offererPaymentAccountId = offererPaymentAccountId;
this.arbitratorNodeAddresses = arbitratorNodeAddresses;
this.acceptedCountryCodes = acceptedCountryCodes;
this.acceptedBanks = acceptedBanks;
protocolVersion = Version.TRADE_PROTOCOL_VERSION;
@ -336,6 +340,11 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
return acceptedCountryCodes;
}
@Nullable
public List<String> getAcceptedBanks() {
return acceptedBanks;
}
public String getOfferFeePaymentTxID() {
return offerFeePaymentTxID;
}
@ -389,6 +398,8 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
return false;
if (acceptedCountryCodes != null ? !acceptedCountryCodes.equals(offer.acceptedCountryCodes) : offer.acceptedCountryCodes != null)
return false;
if (acceptedBanks != null ? !acceptedBanks.equals(offer.acceptedBanks) : offer.acceptedBanks != null)
return false;
if (arbitratorNodeAddresses != null ? !arbitratorNodeAddresses.equals(offer.arbitratorNodeAddresses) : offer.arbitratorNodeAddresses != null)
return false;
return !(offerFeePaymentTxID != null ? !offerFeePaymentTxID.equals(offer.offerFeePaymentTxID) : offer.offerFeePaymentTxID != null);
@ -410,6 +421,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
result = 31 * result + (paymentMethodCountryCode != null ? paymentMethodCountryCode.hashCode() : 0);
result = 31 * result + (offererPaymentAccountId != null ? offererPaymentAccountId.hashCode() : 0);
result = 31 * result + (acceptedCountryCodes != null ? acceptedCountryCodes.hashCode() : 0);
result = 31 * result + (acceptedBanks != null ? acceptedBanks.hashCode() : 0);
result = 31 * result + (arbitratorNodeAddresses != null ? arbitratorNodeAddresses.hashCode() : 0);
result = 31 * result + (offerFeePaymentTxID != null ? offerFeePaymentTxID.hashCode() : 0);
return result;
@ -431,6 +443,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
"\n\tpaymentMethodCountryCode='" + paymentMethodCountryCode + '\'' +
"\n\toffererPaymentAccountId='" + offererPaymentAccountId + '\'' +
"\n\tacceptedCountryCodes=" + acceptedCountryCodes +
"\n\tacceptedBanks=" + acceptedBanks +
"\n\tarbitratorAddresses=" + arbitratorNodeAddresses +
"\n\tofferFeePaymentTxID='" + offerFeePaymentTxID + '\'' +
"\n\tstate=" + state +

View File

@ -22,10 +22,7 @@ import io.bitsquare.app.Version;
import io.bitsquare.btc.BitcoinNetwork;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.common.persistance.Persistable;
import io.bitsquare.locale.CountryUtil;
import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.locale.FiatCurrency;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.locale.*;
import io.bitsquare.storage.Storage;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
@ -33,6 +30,7 @@ import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
@ -94,7 +92,8 @@ public final class Preferences implements Persistable {
private String btcDenomination = MonetaryFormat.CODE_BTC;
private boolean useAnimations = true;
private boolean useEffects = true;
private final ArrayList<TradeCurrency> tradeCurrencies;
private final ArrayList<FiatCurrency> fiatCurrencies;
private final ArrayList<CryptoCurrency> cryptoCurrencies;
private BlockChainExplorer blockChainExplorerMainNet;
private BlockChainExplorer blockChainExplorerTestNet;
private boolean showNotifications = true;
@ -112,6 +111,8 @@ public final class Preferences implements Persistable {
transient private final StringProperty btcDenominationProperty = new SimpleStringProperty(btcDenomination);
transient private final BooleanProperty useAnimationsProperty = new SimpleBooleanProperty(useAnimations);
transient private final BooleanProperty useEffectsProperty = new SimpleBooleanProperty(useEffects);
transient private final ObservableList<FiatCurrency> fiatCurrenciesAsObservable = FXCollections.observableArrayList();
transient private final ObservableList<CryptoCurrency> cryptoCurrenciesAsObservable = FXCollections.observableArrayList();
transient private final ObservableList<TradeCurrency> tradeCurrenciesAsObservable = FXCollections.observableArrayList();
@ -130,8 +131,12 @@ public final class Preferences implements Persistable {
setBtcDenomination(persisted.btcDenomination);
setUseAnimations(persisted.useAnimations);
setUseEffects(persisted.useEffects);
setTradeCurrencies(persisted.tradeCurrencies);
tradeCurrencies = new ArrayList<>(tradeCurrenciesAsObservable);
setFiatCurrencies(persisted.fiatCurrencies);
fiatCurrencies = new ArrayList<>(fiatCurrenciesAsObservable);
setCryptoCurrencies(persisted.cryptoCurrencies);
cryptoCurrencies = new ArrayList<>(cryptoCurrenciesAsObservable);
setBlockChainExplorerTestNet(persisted.getBlockChainExplorerTestNet());
setBlockChainExplorerMainNet(persisted.getBlockChainExplorerMainNet());
@ -160,8 +165,12 @@ public final class Preferences implements Persistable {
// leave default value
}
} else {
setTradeCurrencies(CurrencyUtil.getAllSortedCurrencies());
tradeCurrencies = new ArrayList<>(tradeCurrenciesAsObservable);
setFiatCurrencies(CurrencyUtil.getAllMainFiatCurrencies());
fiatCurrencies = new ArrayList<>(fiatCurrenciesAsObservable);
setCryptoCurrencies(CurrencyUtil.getMainCryptoCurrencies());
cryptoCurrencies = new ArrayList<>(cryptoCurrenciesAsObservable);
setBlockChainExplorerTestNet(blockChainExplorersTestNet.get(0));
setBlockChainExplorerMainNet(blockChainExplorersMainNet.get(0));
@ -193,11 +202,21 @@ public final class Preferences implements Persistable {
useEffects = useEffectsProperty.get();
storage.queueUpForSave(2000);
});
tradeCurrenciesAsObservable.addListener((Observable ov) -> {
tradeCurrencies.clear();
tradeCurrencies.addAll(tradeCurrenciesAsObservable);
fiatCurrenciesAsObservable.addListener((Observable ov) -> {
fiatCurrencies.clear();
fiatCurrencies.addAll(fiatCurrenciesAsObservable);
storage.queueUpForSave();
});
cryptoCurrenciesAsObservable.addListener((Observable ov) -> {
cryptoCurrencies.clear();
cryptoCurrencies.addAll(cryptoCurrenciesAsObservable);
storage.queueUpForSave();
});
fiatCurrenciesAsObservable.addListener((ListChangeListener<FiatCurrency>) this::updateTradeCurrencies);
cryptoCurrenciesAsObservable.addListener((ListChangeListener<CryptoCurrency>) this::updateTradeCurrencies);
tradeCurrenciesAsObservable.addAll(fiatCurrencies);
tradeCurrenciesAsObservable.addAll(cryptoCurrencies);
}
public void dontShowAgain(String id) {
@ -205,6 +224,14 @@ public final class Preferences implements Persistable {
storage.queueUpForSave(2000);
}
private void updateTradeCurrencies(ListChangeListener.Change<? extends TradeCurrency> change) {
change.next();
if (change.wasAdded() && change.getAddedSize() == 1)
tradeCurrenciesAsObservable.add(change.getAddedSubList().get(0));
else if (change.wasRemoved() && change.getRemovedSize() == 1)
tradeCurrenciesAsObservable.remove(change.getRemoved().get(0));
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setter
@ -231,8 +258,46 @@ public final class Preferences implements Persistable {
// We don't store the bitcoinNetwork locally as BitcoinNetwork is not serializable!
}
private void setTradeCurrencies(List<TradeCurrency> tradeCurrencies) {
tradeCurrenciesAsObservable.setAll(tradeCurrencies);
private void setFiatCurrencies(List<FiatCurrency> currencies) {
fiatCurrenciesAsObservable.setAll(currencies);
}
private void setCryptoCurrencies(List<CryptoCurrency> currencies) {
cryptoCurrenciesAsObservable.setAll(currencies);
}
public void addFiatCurrency(FiatCurrency tradeCurrency) {
if (!fiatCurrenciesAsObservable.contains(tradeCurrency))
fiatCurrenciesAsObservable.add(tradeCurrency);
}
public void removeFiatCurrency(FiatCurrency tradeCurrency) {
if (tradeCurrenciesAsObservable.size() > 1) {
if (fiatCurrenciesAsObservable.contains(tradeCurrency))
fiatCurrenciesAsObservable.remove(tradeCurrency);
if (preferredTradeCurrency.equals(tradeCurrency))
setPreferredTradeCurrency(tradeCurrenciesAsObservable.get(0));
} else {
log.error("you cannot remove the last currency");
}
}
public void addCryptoCurrency(CryptoCurrency tradeCurrency) {
if (!cryptoCurrenciesAsObservable.contains(tradeCurrency))
cryptoCurrenciesAsObservable.add(tradeCurrency);
}
public void removeCryptoCurrency(CryptoCurrency tradeCurrency) {
if (tradeCurrenciesAsObservable.size() > 1) {
if (cryptoCurrenciesAsObservable.contains(tradeCurrency))
cryptoCurrenciesAsObservable.remove(tradeCurrency);
if (preferredTradeCurrency.equals(tradeCurrency))
setPreferredTradeCurrency(tradeCurrenciesAsObservable.get(0));
} else {
log.error("you cannot remove the last currency");
}
}
private void setBlockChainExplorerTestNet(BlockChainExplorer blockChainExplorerTestNet) {
@ -274,9 +339,11 @@ public final class Preferences implements Persistable {
}
public void setPreferredTradeCurrency(TradeCurrency preferredTradeCurrency) {
this.preferredTradeCurrency = preferredTradeCurrency;
defaultTradeCurrency = preferredTradeCurrency;
storage.queueUpForSave();
if (preferredTradeCurrency != null) {
this.preferredTradeCurrency = preferredTradeCurrency;
defaultTradeCurrency = preferredTradeCurrency;
storage.queueUpForSave();
}
}
public void setTxFeePerKB(long txFeePerKB) throws Exception {
@ -329,6 +396,14 @@ public final class Preferences implements Persistable {
return bitcoinNetwork;
}
public ObservableList<FiatCurrency> getFiatCurrenciesAsObservable() {
return fiatCurrenciesAsObservable;
}
public ObservableList<CryptoCurrency> getCryptoCurrenciesAsObservable() {
return cryptoCurrenciesAsObservable;
}
public ObservableList<TradeCurrency> getTradeCurrenciesAsObservable() {
return tradeCurrenciesAsObservable;
}

View File

@ -53,14 +53,15 @@ abstract class BankForm extends PaymentMethodForm {
static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
BankAccountContractData bankAccountContractData = (BankAccountContractData) paymentAccountContractData;
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account holder name:", bankAccountContractData.getHolderName());
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Country of bank:", CountryUtil.getNameAndCode(bankAccountContractData.getCountryCode()));
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Bank name:", bankAccountContractData.getBankName());
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Bank number:", bankAccountContractData.getBankId());
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Branch number:", bankAccountContractData.getBranchId());
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account number:", bankAccountContractData.getAccountNr());
if (bankAccountContractData.getHolderId() != null)
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, bankAccountContractData.getHolderIdLabel(), bankAccountContractData.getHolderId());
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account holder name / " + bankAccountContractData.getHolderIdLabel(),
bankAccountContractData.getHolderName() + " / " + bankAccountContractData.getHolderId());
else
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account holder name:", bankAccountContractData.getHolderName());
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Country of bank:", CountryUtil.getNameAndCode(bankAccountContractData.getCountryCode()));
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Bank name / number:", bankAccountContractData.getBankName() + " / " + bankAccountContractData.getBankId());
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Branch number / Account number:", bankAccountContractData.getBranchId() + " / " + bankAccountContractData.getAccountNr());
return gridRow;
}

View File

@ -114,7 +114,7 @@ public class BlockChainForm extends PaymentMethodForm {
protected void addTradeCurrencyComboBox() {
currencyComboBox = addLabelComboBox(gridPane, ++gridRow, "Crypto currency:", Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
currencyComboBox.setPromptText("Select cryptocurrency");
currencyComboBox.setItems(FXCollections.observableArrayList(CurrencyUtil.getSortedCryptoCurrencies()));
currencyComboBox.setItems(FXCollections.observableArrayList(CurrencyUtil.getAllSortedCryptoCurrencies()));
currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 20));
currencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
@Override

View File

@ -28,8 +28,7 @@ public class NationalBankForm extends BankForm {
private static final Logger log = LoggerFactory.getLogger(NationalBankForm.class);
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
BankForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData);
return gridRow;
return BankForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData);
}
public NationalBankForm(PaymentAccount paymentAccount, InputValidator inputValidator,

View File

@ -61,7 +61,7 @@ public abstract class PaymentMethodForm {
protected void addTradeCurrencyComboBox() {
currencyComboBox = addLabelComboBox(gridPane, ++gridRow, "Currency:").second;
currencyComboBox.setPromptText("Select currency");
currencyComboBox.setItems(FXCollections.observableArrayList(CurrencyUtil.getAllSortedCurrencies()));
currencyComboBox.setItems(FXCollections.observableArrayList(CurrencyUtil.getAllMainFiatCurrencies()));
currencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
@Override
public String toString(TradeCurrency tradeCurrency) {

View File

@ -35,8 +35,7 @@ public class SameBankForm extends BankForm {
private static final Logger log = LoggerFactory.getLogger(SameBankForm.class);
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
BankForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData);
return gridRow;
return BankForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData);
}
public SameBankForm(PaymentAccount paymentAccount, InputValidator inputValidator,
@ -72,10 +71,7 @@ public class SameBankForm extends BankForm {
Tuple2<Label, TextField> tuple = addLabelTextField(gridPane, ++gridRow, "Account holder name:");
TextField holderNameTextField = tuple.second;
holderNameTextField.setMinWidth(300);
holderNameTextField.textProperty().addListener((ov, oldValue, newValue) -> {
bankAccountContractData.setHolderName(newValue);
updateFromInputs();
});
holderNameTextField.setText(bankAccountContractData.getHolderName());
}
}

View File

@ -43,8 +43,7 @@ public class SpecificBankForm extends BankForm {
private Tooltip acceptedBanksTooltip;
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
BankForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData);
return gridRow;
return BankForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData);
}
public SpecificBankForm(PaymentAccount paymentAccount, InputValidator inputValidator,

View File

@ -20,15 +20,24 @@ package io.bitsquare.gui.main.account.content.altcoinaccounts;
import com.google.inject.Inject;
import io.bitsquare.gui.common.model.ActivatableWithDataModel;
import io.bitsquare.gui.common.model.ViewModel;
import io.bitsquare.locale.CryptoCurrency;
import io.bitsquare.locale.FiatCurrency;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.user.Preferences;
import javafx.collections.ObservableList;
import java.util.List;
class AltCoinAccountsViewModel extends ActivatableWithDataModel<AltCoinAccountsDataModel> implements ViewModel {
private Preferences preferences;
@Inject
public AltCoinAccountsViewModel(AltCoinAccountsDataModel dataModel) {
public AltCoinAccountsViewModel(AltCoinAccountsDataModel dataModel, Preferences preferences) {
super(dataModel);
this.preferences = preferences;
}
@Override
@ -46,6 +55,21 @@ class AltCoinAccountsViewModel extends ActivatableWithDataModel<AltCoinAccountsD
public void onSaveNewAccount(PaymentAccount paymentAccount) {
dataModel.onSaveNewAccount(paymentAccount);
TradeCurrency singleTradeCurrency = paymentAccount.getSingleTradeCurrency();
List<TradeCurrency> tradeCurrencies = paymentAccount.getTradeCurrencies();
if (singleTradeCurrency != null) {
if (singleTradeCurrency instanceof FiatCurrency)
preferences.addFiatCurrency((FiatCurrency) singleTradeCurrency);
else
preferences.addCryptoCurrency((CryptoCurrency) singleTradeCurrency);
} else if (tradeCurrencies != null && !tradeCurrencies.isEmpty()) {
tradeCurrencies.stream().forEach(tradeCurrency -> {
if (tradeCurrency instanceof FiatCurrency)
preferences.addFiatCurrency((FiatCurrency) tradeCurrency);
else
preferences.addCryptoCurrency((CryptoCurrency) tradeCurrency);
});
}
}
public void onDeleteAccount(PaymentAccount paymentAccount) {

View File

@ -19,8 +19,12 @@ package io.bitsquare.gui.main.account.content.fiataccounts;
import com.google.inject.Inject;
import io.bitsquare.gui.common.model.ActivatableDataModel;
import io.bitsquare.locale.CryptoCurrency;
import io.bitsquare.locale.FiatCurrency;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.payment.PaymentMethod;
import io.bitsquare.user.Preferences;
import io.bitsquare.user.User;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
@ -32,12 +36,14 @@ import java.util.stream.Collectors;
class FiatAccountsDataModel extends ActivatableDataModel {
private final User user;
private Preferences preferences;
final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList();
private final SetChangeListener<PaymentAccount> setChangeListener;
@Inject
public FiatAccountsDataModel(User user) {
public FiatAccountsDataModel(User user, Preferences preferences) {
this.user = user;
this.preferences = preferences;
setChangeListener = change -> fillAndSortPaymentAccounts();
}
@ -67,6 +73,21 @@ class FiatAccountsDataModel extends ActivatableDataModel {
public void onSaveNewAccount(PaymentAccount paymentAccount) {
user.addPaymentAccount(paymentAccount);
TradeCurrency singleTradeCurrency = paymentAccount.getSingleTradeCurrency();
List<TradeCurrency> tradeCurrencies = paymentAccount.getTradeCurrencies();
if (singleTradeCurrency != null) {
if (singleTradeCurrency instanceof FiatCurrency)
preferences.addFiatCurrency((FiatCurrency) singleTradeCurrency);
else
preferences.addCryptoCurrency((CryptoCurrency) singleTradeCurrency);
} else if (tradeCurrencies != null && !tradeCurrencies.isEmpty()) {
tradeCurrencies.stream().forEach(tradeCurrency -> {
if (tradeCurrency instanceof FiatCurrency)
preferences.addFiatCurrency((FiatCurrency) tradeCurrency);
else
preferences.addCryptoCurrency((CryptoCurrency) tradeCurrency);
});
}
}
public void onDeleteAccount(PaymentAccount paymentAccount) {

View File

@ -149,6 +149,7 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
protected void deactivate() {
model.getOfferBookListItems().removeListener(changeListener);
tradeCurrencySubscriber.unsubscribe();
currencyComboBox.setOnAction(null);
}

View File

@ -36,7 +36,9 @@ import io.bitsquare.locale.Country;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.p2p.P2PService;
import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.payment.SameBankAccount;
import io.bitsquare.payment.SepaAccount;
import io.bitsquare.payment.SpecificBankAccount;
import io.bitsquare.trade.handlers.TransactionResultHandler;
import io.bitsquare.trade.offer.Offer;
import io.bitsquare.trade.offer.OpenOfferManager;
@ -242,6 +244,12 @@ class CreateOfferDataModel extends ActivatableDataModel {
if (paymentAccount instanceof SepaAccount)
acceptedCountryCodes.addAll(((SepaAccount) paymentAccount).getAcceptedCountryCodes());
ArrayList<String> acceptedBanks = new ArrayList<>();
if (paymentAccount instanceof SpecificBankAccount)
acceptedBanks.addAll(((SpecificBankAccount) paymentAccount).getAcceptedBanks());
else if (paymentAccount instanceof SameBankAccount)
acceptedBanks.add(((SameBankAccount) paymentAccount).getAcceptedBank());
// That is optional and set to null if not supported (AltCoins, OKPay,...)
Country country = paymentAccount.getCountry();
@ -258,7 +266,8 @@ class CreateOfferDataModel extends ActivatableDataModel {
country,
paymentAccount.getId(),
new ArrayList<>(user.getAcceptedArbitratorAddresses()),
acceptedCountryCodes);
acceptedCountryCodes,
acceptedBanks);
}
void onPlaceOffer(Offer offer, TransactionResultHandler resultHandler) {

View File

@ -17,6 +17,7 @@
package io.bitsquare.gui.main.offer.offerbook;
import com.google.common.base.Joiner;
import com.google.inject.Inject;
import io.bitsquare.app.Version;
import io.bitsquare.btc.pricefeed.PriceFeed;
@ -60,6 +61,7 @@ class OfferBookViewModel extends ActivatableViewModel {
private final FilteredList<OfferBookListItem> filteredItems;
private final SortedList<OfferBookListItem> sortedItems;
private final ListChangeListener<TradeCurrency> tradeCurrencyListChangeListener;
private TradeCurrency selectedTradeCurrency;
private final ObservableList<TradeCurrency> allTradeCurrencies = FXCollections.observableArrayList();
@ -106,13 +108,7 @@ class OfferBookViewModel extends ActivatableViewModel {
selectedTradeCurrency = CurrencyUtil.getDefaultTradeCurrency();
tradeCurrencyCode.set(selectedTradeCurrency.getCode());
preferences.getTradeCurrenciesAsObservable().addListener(new ListChangeListener<TradeCurrency>() {
@Override
public void onChanged(Change<? extends TradeCurrency> c) {
fillAllTradeCurrencies();
}
});
tradeCurrencyListChangeListener = c -> fillAllTradeCurrencies();
}
@Override
@ -120,6 +116,7 @@ class OfferBookViewModel extends ActivatableViewModel {
fillAllTradeCurrencies();
btcCode.bind(preferences.btcDenominationProperty());
offerBookListItems.addListener(listChangeListener);
preferences.getTradeCurrenciesAsObservable().addListener(tradeCurrencyListChangeListener);
offerBook.fillOfferBookListItems();
filterList();
setMarketPriceFeedCurrency();
@ -130,6 +127,7 @@ class OfferBookViewModel extends ActivatableViewModel {
protected void deactivate() {
btcCode.unbind();
offerBookListItems.removeListener(listChangeListener);
preferences.getTradeCurrenciesAsObservable().removeListener(tradeCurrencyListChangeListener);
}
private void fillAllTradeCurrencies() {
@ -255,7 +253,7 @@ class OfferBookViewModel extends ActivatableViewModel {
String result = "";
if (item != null) {
Offer offer = item.getOffer();
String method = BSResources.get(offer.getPaymentMethod().getId());
String method = BSResources.get(offer.getPaymentMethod().getId() + "_SHORT");
String methodCountryCode = offer.getPaymentMethodCountryCode();
if (methodCountryCode != null)
@ -279,11 +277,17 @@ class OfferBookViewModel extends ActivatableViewModel {
result = method;
List<String> acceptedCountryCodes = offer.getAcceptedCountryCodes();
if (acceptedCountryCodes != null && acceptedCountryCodes.size() > 0) {
List<String> acceptedBanks = offer.getAcceptedBanks();
if (acceptedCountryCodes != null && !acceptedCountryCodes.isEmpty()) {
if (CountryUtil.containsAllSepaEuroCountries(acceptedCountryCodes))
result += "\n\nAccepted takers seat of bank countries:\nAll Euro countries";
else
result += "\n\nAccepted taker seat of bank countries:\n" + CountryUtil.getNamesByCodesString(acceptedCountryCodes);
} else if (acceptedBanks != null && !acceptedBanks.isEmpty()) {
if (offer.getPaymentMethod().equals(PaymentMethod.SAME_BANK))
result += "\n\nBank name: " + acceptedBanks.get(0);
else if (offer.getPaymentMethod().equals(PaymentMethod.SPECIFIC_BANKS))
result += "\n\nAccepted banks: " + Joiner.on(", ").join(acceptedBanks);
}
}
return result;
@ -303,7 +307,7 @@ class OfferBookViewModel extends ActivatableViewModel {
}
boolean isPaymentAccountValidForOffer(Offer offer) {
// TODO not supporting yet check for acceptedBanks in cae of SpecificBankAccount and SameBankAccount
Optional<TradeCurrency> result1 = user.getPaymentAccounts().stream()
.filter(paymentAccount -> paymentAccount.getPaymentMethod().equals(offer.getPaymentMethod()))
.filter(paymentAccount -> {

View File

@ -17,6 +17,7 @@
package io.bitsquare.gui.main.popups;
import com.google.common.base.Joiner;
import io.bitsquare.arbitration.Dispute;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.Layout;
@ -24,6 +25,7 @@ import io.bitsquare.locale.BSResources;
import io.bitsquare.locale.CountryUtil;
import io.bitsquare.payment.BlockChainAccountContractData;
import io.bitsquare.payment.PaymentAccountContractData;
import io.bitsquare.payment.PaymentMethod;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.offer.Offer;
import javafx.geometry.Insets;
@ -35,6 +37,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.util.List;
import java.util.Optional;
import static io.bitsquare.gui.util.FormBuilder.*;
@ -90,12 +93,19 @@ public class ContractPopup extends Popup {
Contract contract = dispute.getContract();
Offer offer = contract.offer;
List<String> acceptedBanks = offer.getAcceptedBanks();
boolean showAcceptedBanks = acceptedBanks != null && !acceptedBanks.isEmpty();
List<String> acceptedCountryCodes = offer.getAcceptedCountryCodes();
boolean showAcceptedCountryCodes = acceptedCountryCodes != null && !acceptedCountryCodes.isEmpty();
int rows = 16;
if (dispute.getDepositTxSerialized() != null)
rows++;
if (dispute.getPayoutTxSerialized() != null)
rows++;
if (offer.getAcceptedCountryCodes() != null)
if (showAcceptedCountryCodes)
rows++;
if (showAcceptedBanks)
rows++;
boolean isPaymentIdAvailable = false;
@ -130,20 +140,31 @@ public class ContractPopup extends Popup {
addLabelTextField(gridPane, ++rowIndex, "Seller payment ID:",
((BlockChainAccountContractData) sellerPaymentAccountContractData).getPaymentId());
if (offer.getAcceptedCountryCodes() != null && !offer.getAcceptedCountryCodes().isEmpty()) {
if (showAcceptedCountryCodes) {
String countries;
Tooltip tooltip = null;
if (CountryUtil.containsAllSepaEuroCountries(offer.getAcceptedCountryCodes())) {
if (CountryUtil.containsAllSepaEuroCountries(acceptedCountryCodes)) {
countries = "All Euro countries";
} else {
countries = CountryUtil.getCodesString(offer.getAcceptedCountryCodes());
tooltip = new Tooltip(CountryUtil.getNamesByCodesString(offer.getAcceptedCountryCodes()));
countries = CountryUtil.getCodesString(acceptedCountryCodes);
tooltip = new Tooltip(CountryUtil.getNamesByCodesString(acceptedCountryCodes));
}
TextField acceptedCountries = addLabelTextField(gridPane, ++rowIndex, "Accepted taker countries:", countries).second;
if (tooltip != null) acceptedCountries.setTooltip(new Tooltip());
}
//addLabelTextField(gridPane, ++rowIndex, "Buyer Bitsquare account ID:", contract.getBuyerAccountId()).second.setMouseTransparent(false);
//addLabelTextField(gridPane, ++rowIndex, "Seller Bitsquare account ID:", contract.getSellerAccountId()).second.setMouseTransparent(false);
if (showAcceptedBanks) {
if (offer.getPaymentMethod().equals(PaymentMethod.SAME_BANK)) {
addLabelTextField(gridPane, ++rowIndex, "Bank name:", acceptedBanks.get(0));
} else if (offer.getPaymentMethod().equals(PaymentMethod.SPECIFIC_BANKS)) {
String value = Joiner.on(", ").join(acceptedBanks);
Tooltip tooltip = new Tooltip("Accepted banks: " + value);
TextField acceptedBanksTextField = addLabelTextField(gridPane, ++rowIndex, "Accepted banks:", value).second;
acceptedBanksTextField.setMouseTransparent(false);
acceptedBanksTextField.setTooltip(tooltip);
}
}
addLabelTxIdTextField(gridPane, ++rowIndex, "Offer fee transaction ID:", offer.getOfferFeePaymentTxID());
addLabelTxIdTextField(gridPane, ++rowIndex, "Trading fee transaction ID:", contract.takeOfferFeeTxID);
if (dispute.getDepositTxSerialized() != null)

View File

@ -17,6 +17,7 @@
package io.bitsquare.gui.main.popups;
import com.google.common.base.Joiner;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.gui.Navigation;
@ -28,6 +29,7 @@ import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.Layout;
import io.bitsquare.locale.BSResources;
import io.bitsquare.locale.CountryUtil;
import io.bitsquare.payment.PaymentMethod;
import io.bitsquare.trade.offer.Offer;
import io.bitsquare.user.Preferences;
import io.bitsquare.user.User;
@ -41,6 +43,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
@ -134,8 +137,18 @@ public class OfferDetailsPopup extends Popup {
private void addContent() {
int rows = 5;
List<String> acceptedBanks = offer.getAcceptedBanks();
boolean showAcceptedBanks = acceptedBanks != null && !acceptedBanks.isEmpty();
List<String> acceptedCountryCodes = offer.getAcceptedCountryCodes();
boolean showAcceptedCountryCodes = acceptedCountryCodes != null && !acceptedCountryCodes.isEmpty();
if (!takeOfferHandlerOptional.isPresent())
rows++;
if (showAcceptedBanks)
rows++;
if (showAcceptedCountryCodes)
rows++;
addTitledGroupBg(gridPane, ++rowIndex, rows, "Offer");
@ -154,22 +167,46 @@ public class OfferDetailsPopup extends Popup {
addLabelTextField(gridPane, ++rowIndex, "Price:", formatter.formatFiat(offer.getPrice()) + " " + offer.getCurrencyCode() + "/" + "BTC");
addLabelTextField(gridPane, ++rowIndex, "Currency:", offer.getCurrencyCode());
if (offer.isMyOffer(keyRing) && user.getPaymentAccount(offer.getOffererPaymentAccountId()) != null)
addLabelTextField(gridPane, ++rowIndex, "Payment account:", user.getPaymentAccount(offer.getOffererPaymentAccountId()).getAccountName());
else
addLabelTextField(gridPane, ++rowIndex, "Payment method:", BSResources.get(offer.getPaymentMethod().getId()));
if (showAcceptedBanks) {
if (offer.getPaymentMethod().equals(PaymentMethod.SAME_BANK)) {
addLabelTextField(gridPane, ++rowIndex, "Bank name:", acceptedBanks.get(0));
} else if (offer.getPaymentMethod().equals(PaymentMethod.SPECIFIC_BANKS)) {
String value = Joiner.on(", ").join(acceptedBanks);
Tooltip tooltip = new Tooltip("Accepted banks: " + value);
TextField acceptedBanksTextField = addLabelTextField(gridPane, ++rowIndex, "Accepted banks:", value).second;
acceptedBanksTextField.setMouseTransparent(false);
acceptedBanksTextField.setTooltip(tooltip);
}
}
if (showAcceptedCountryCodes) {
String countries;
Tooltip tooltip = null;
if (CountryUtil.containsAllSepaEuroCountries(acceptedCountryCodes)) {
countries = "All Euro countries";
} else {
countries = CountryUtil.getCodesString(acceptedCountryCodes);
tooltip = new Tooltip(CountryUtil.getNamesByCodesString(acceptedCountryCodes));
}
TextField acceptedCountries = addLabelTextField(gridPane, ++rowIndex, "Accepted taker countries:", countries).second;
if (tooltip != null) {
acceptedCountries.setMouseTransparent(false);
acceptedCountries.setTooltip(tooltip);
}
}
rows = 3;
String paymentMethodCountryCode = offer.getPaymentMethodCountryCode();
if (paymentMethodCountryCode != null)
rows++;
if (offer.getOfferFeePaymentTxID() != null)
rows++;
if (offer.getAcceptedCountryCodes() != null)
rows++;
/* if (placeOfferHandlerOptional.isPresent())
rows -= 2;*/
addTitledGroupBg(gridPane, ++rowIndex, rows, "Details", Layout.GROUP_DISTANCE);
addLabelTextField(gridPane, rowIndex, "Offer ID:", offer.getId(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
@ -178,21 +215,7 @@ public class OfferDetailsPopup extends Popup {
if (paymentMethodCountryCode != null)
addLabelTextField(gridPane, ++rowIndex, "Offerers country of bank:",
CountryUtil.getNameAndCode(paymentMethodCountryCode));
if (offer.getAcceptedCountryCodes() != null) {
String countries;
Tooltip tooltip = null;
if (CountryUtil.containsAllSepaEuroCountries(offer.getAcceptedCountryCodes())) {
countries = "All Euro countries";
} else {
countries = CountryUtil.getCodesString(offer.getAcceptedCountryCodes());
tooltip = new Tooltip(CountryUtil.getNamesByCodesString(offer.getAcceptedCountryCodes()));
}
TextField acceptedCountries = addLabelTextField(gridPane, ++rowIndex, "Accepted taker countries:", countries).second;
if (tooltip != null) {
acceptedCountries.setMouseTransparent(false);
acceptedCountries.setTooltip(tooltip);
}
}
addLabelTextField(gridPane, ++rowIndex, "Accepted arbitrators:", formatter.arbitratorAddressesToString(offer.getArbitratorNodeAddresses()));
if (offer.getOfferFeePaymentTxID() != null)
addLabelTxIdTextField(gridPane, ++rowIndex, "Offer fee transaction ID:", offer.getOfferFeePaymentTxID());

View File

@ -123,8 +123,10 @@ public class TradeDetailsPopup extends Popup {
PaymentAccountContractData buyerPaymentAccountContractData = null;
PaymentAccountContractData sellerPaymentAccountContractData = null;
if (offer.getAcceptedCountryCodes() != null)
/* if (offer.getAcceptedCountryCodes() != null)
rows++;
if (offer.getAcceptedBanks() != null)
rows++;*/
if (contract != null) {
rows++;

View File

@ -112,7 +112,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
if (selectedItem != null)
tradeStateSubscription = EasyBind.subscribe(selectedItem.getTrade().stateProperty(), this::onTradeStateChanged);
}
@Override
protected void deactivate() {
if (tradeStateSubscription != null) {
@ -185,7 +185,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
String result = "";
if (item != null) {
Offer offer = item.getTrade().getOffer();
String method = BSResources.get(offer.getPaymentMethod().getId());
String method = BSResources.get(offer.getPaymentMethod().getId() + "_SHORT");
String methodCountryCode = offer.getPaymentMethodCountryCode();
if (methodCountryCode != null)

View File

@ -25,6 +25,6 @@
AnchorPane.rightAnchor="0" AnchorPane.topAnchor="0"
xmlns:fx="http://javafx.com/fxml">
<Tab fx:id="networkSettingsTab" text="Network info" closable="false"/>
<Tab fx:id="preferencesTab" text="Preferences" closable="false"/>
<Tab fx:id="networkSettingsTab" text="Network info" closable="false"/>
</TabPane>

View File

@ -80,6 +80,7 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
@Inject
public NetworkSettingsView(WalletService walletService, P2PService p2PService, Preferences preferences, Clock clock,
BSFormatter formatter) {
super();
this.walletService = walletService;
this.p2PService = p2PService;
this.preferences = preferences;

View File

@ -1,75 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.settings.preferences;
import com.google.inject.Inject;
import io.bitsquare.gui.common.model.ActivatableDataModel;
import io.bitsquare.user.Preferences;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
class PreferencesDataModel extends ActivatableDataModel {
private final Preferences preferences;
private final ChangeListener<Boolean> useAnimationsListener;
private final ChangeListener<Boolean> useEffectsListener;
private final ChangeListener<String> btcDenominationListener;
private final ObservableList<String> btcDenominations;
private final BooleanProperty useAnimations = new SimpleBooleanProperty();
private final BooleanProperty useEffects = new SimpleBooleanProperty();
private final StringProperty btcDenomination = new SimpleStringProperty();
@Inject
public PreferencesDataModel(Preferences preferences) {
this.preferences = preferences;
btcDenominations = FXCollections.observableArrayList(Preferences.getBtcDenominations());
btcDenominationListener = (ov, oldValue, newValue) -> preferences.setBtcDenomination(newValue);
useAnimationsListener = (ov, oldValue, newValue) -> preferences.setUseAnimations(newValue);
useEffectsListener = (ov, oldValue, newValue) -> preferences.setUseEffects(newValue);
}
@Override
protected void activate() {
useAnimations.set(preferences.getUseAnimations());
useEffects.set(preferences.getUseEffects());
btcDenomination.set(preferences.getBtcDenomination());
useAnimations.addListener(useAnimationsListener);
useEffects.addListener(useEffectsListener);
btcDenomination.addListener(btcDenominationListener);
}
@Override
protected void deactivate() {
useAnimations.removeListener(useAnimationsListener);
useEffects.removeListener(useEffectsListener);
btcDenomination.removeListener(btcDenominationListener);
}
}

View File

@ -32,5 +32,7 @@
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" halignment="RIGHT" minWidth="140.0"/>
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
<ColumnConstraints hgrow="SOMETIMES" halignment="RIGHT" minWidth="140.0"/>
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
</columnConstraints>
</GridPane>

View File

@ -17,30 +17,44 @@
package io.bitsquare.gui.main.settings.preferences;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.gui.common.model.Activatable;
import io.bitsquare.gui.common.view.ActivatableViewAndModel;
import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.components.TitledGroupBg;
import io.bitsquare.gui.main.popups.Popup;
import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.gui.util.Layout;
import io.bitsquare.locale.LanguageUtil;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.locale.*;
import io.bitsquare.user.BlockChainExplorer;
import io.bitsquare.user.Preferences;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.util.Callback;
import javafx.util.StringConverter;
import javax.inject.Inject;
import java.util.Locale;
import static io.bitsquare.gui.util.FormBuilder.*;
@FxmlView
public class PreferencesView extends ActivatableViewAndModel<GridPane, PreferencesViewModel> {
public class PreferencesView extends ActivatableViewAndModel<GridPane, Activatable> {
// not supported yet
//private ComboBox<String> btcDenominationComboBox;
private ComboBox<BlockChainExplorer> blockChainExplorerComboBox;
private ComboBox<String> languageComboBox;
private ComboBox<String> userLanguageComboBox;
private ComboBox<TradeCurrency> preferredTradeCurrencyComboBox;
private CheckBox useAnimationsCheckBox, useEffectsCheckBox, showNotificationsCheckBox, showInstructionsCheckBox,
@ -50,43 +64,76 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
private ChangeListener<Boolean> transactionFeeFocusedListener;
private final Preferences preferences;
private ListView<FiatCurrency> fiatCurrenciesListView;
private ComboBox<FiatCurrency> fiatCurrenciesComboBox;
private ListView<CryptoCurrency> cryptoCurrenciesListView;
private ComboBox<CryptoCurrency> cryptoCurrenciesComboBox;
// private ListChangeListener<TradeCurrency> displayCurrenciesListChangeListener;
final ObservableList<String> btcDenominations = FXCollections.observableArrayList(Preferences.getBtcDenominations());
final ObservableList<BlockChainExplorer> blockExplorers;
final ObservableList<String> languageCodes;
final StringProperty transactionFeePerByte = new SimpleStringProperty();
public final ObservableList<FiatCurrency> fiatCurrencies;
public final ObservableList<FiatCurrency> allFiatCurrencies;
public final ObservableList<CryptoCurrency> cryptoCurrencies;
public final ObservableList<CryptoCurrency> allCryptoCurrencies;
public final ObservableList<TradeCurrency> tradeCurrencies;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialisation
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public PreferencesView(PreferencesViewModel model, Preferences preferences) {
super(model);
public PreferencesView(Preferences preferences) {
super();
this.preferences = preferences;
blockExplorers = FXCollections.observableArrayList(preferences.getBlockChainExplorers());
languageCodes = FXCollections.observableArrayList(LanguageUtil.getAllLanguageCodes());
fiatCurrencies = preferences.getFiatCurrenciesAsObservable();
cryptoCurrencies = preferences.getCryptoCurrenciesAsObservable();
tradeCurrencies = preferences.getTradeCurrenciesAsObservable();
allFiatCurrencies = FXCollections.observableArrayList(CurrencyUtil.getAllSortedFiatCurrencies());
allCryptoCurrencies = FXCollections.observableArrayList(CurrencyUtil.getAllSortedCryptoCurrencies());
allFiatCurrencies.removeAll(fiatCurrencies);
allCryptoCurrencies.removeAll(cryptoCurrencies);
}
@Override
public void initialize() {
addTitledGroupBg(root, gridRow, 4, "Preferences");
preferredTradeCurrencyComboBox = addLabelComboBox(root, gridRow, "Preferred currency:", Layout.FIRST_ROW_DISTANCE).second;
languageComboBox = addLabelComboBox(root, ++gridRow, "Language:").second;
// btcDenominationComboBox = addLabelComboBox(root, ++gridRow, "Bitcoin denomination:").second;
blockChainExplorerComboBox = addLabelComboBox(root, ++gridRow, "Bitcoin block explorer:").second;
autoSelectArbitratorsCheckBox = addLabelCheckBox(root, ++gridRow, "Auto select arbitrators by language:", "").second;
// TODO need a bit extra work to separate trade and non trade tx fees before it can be used
/*transactionFeeInputTextField = addLabelInputTextField(root, ++gridRow, "Transaction fee (satoshi/byte):").second;
transactionFeeFocusedListener = (o, oldValue, newValue) -> {
model.onFocusOutTransactionFeeTextField(oldValue, newValue);
};*/
addTitledGroupBg(root, ++gridRow, 4, "Display options", Layout.GROUP_DISTANCE);
useAnimationsCheckBox = addLabelCheckBox(root, gridRow, "Use animations:", "", Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
useEffectsCheckBox = addLabelCheckBox(root, ++gridRow, "Use effects:", "").second;
showNotificationsCheckBox = addLabelCheckBox(root, ++gridRow, "Show notifications:", "").second;
showInstructionsCheckBox = addLabelCheckBox(root, ++gridRow, "Show instruction popups:", "").second;
initializeDisplayCurrencies();
initializeOtherOptions();
initializeDisplayOptions();
}
@Override
protected void activate() {
/* btcDenominationComboBox.setDisable(true);
btcDenominationComboBox.setItems(model.btcDenominations);
btcDenominationComboBox.getSelectionModel().select(model.getBtcDenomination());
btcDenominationComboBox.setOnAction(e -> model.onSelectBtcDenomination(btcDenominationComboBox.getSelectionModel().getSelectedItem()));*/
activateDisplayCurrencies();
activateOtherOptions();
activateDisplayPreferences();
}
preferredTradeCurrencyComboBox.setItems(model.tradeCurrencies);
preferredTradeCurrencyComboBox.getSelectionModel().select(preferences.getPreferredTradeCurrency());
@Override
protected void deactivate() {
deactivateDisplayCurrencies();
deactivateOtherOptions();
deactivateDisplayPreferences();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Initialize
///////////////////////////////////////////////////////////////////////////////////////////
private void initializeDisplayCurrencies() {
TitledGroupBg titledGroupBg = addTitledGroupBg(root, gridRow, 3, "Currencies");
GridPane.setColumnSpan(titledGroupBg, 4);
preferredTradeCurrencyComboBox = addLabelComboBox(root, gridRow, "Preferred currency:", Layout.FIRST_ROW_DISTANCE).second;
preferredTradeCurrencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
@Override
public String toString(TradeCurrency tradeCurrency) {
@ -98,11 +145,224 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
return null;
}
});
preferredTradeCurrencyComboBox.setOnAction(e -> preferences.setPreferredTradeCurrency(preferredTradeCurrencyComboBox.getSelectionModel().getSelectedItem()));
languageComboBox.setItems(model.languageCodes);
languageComboBox.getSelectionModel().select(model.getLanguageCode());
languageComboBox.setConverter(new StringConverter<String>() {
Tuple2<Label, ListView> fiatTuple = addLabelListView(root, ++gridRow, "Display national currencies:");
GridPane.setValignment(fiatTuple.first, VPos.TOP);
fiatCurrenciesListView = fiatTuple.second;
fiatCurrenciesListView.setMinHeight(2 * Layout.LIST_ROW_HEIGHT + 2);
fiatCurrenciesListView.setMaxHeight(6 * Layout.LIST_ROW_HEIGHT + 2);
Label placeholder = new Label("There are no national currencies selected");
placeholder.setWrapText(true);
fiatCurrenciesListView.setPlaceholder(placeholder);
fiatCurrenciesListView.setCellFactory(new Callback<ListView<FiatCurrency>, ListCell<FiatCurrency>>() {
@Override
public ListCell<FiatCurrency> call(ListView<FiatCurrency> list) {
return new ListCell<FiatCurrency>() {
final Label label = new Label();
final ImageView icon = ImageUtil.getImageViewById(ImageUtil.REMOVE_ICON);
final Button removeButton = new Button("", icon);
final AnchorPane pane = new AnchorPane(label, removeButton);
{
label.setLayoutY(5);
removeButton.setId("icon-button");
AnchorPane.setRightAnchor(removeButton, 0d);
}
@Override
public void updateItem(final FiatCurrency item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
label.setText(item.getNameAndCode());
removeButton.setOnAction(e -> {
if (item.equals(preferences.getPreferredTradeCurrency())) {
new Popup().warning("You cannot remove your selected preferred display currency").show();
} else {
preferences.removeFiatCurrency(item);
if (!allFiatCurrencies.contains(item))
allFiatCurrencies.add(item);
}
});
setGraphic(pane);
} else {
setGraphic(null);
removeButton.setOnAction(null);
}
}
};
}
});
Tuple2<Label, ListView> cryptoCurrenciesTuple = addLabelListView(root, gridRow, "Display crypto currencies:");
GridPane.setValignment(cryptoCurrenciesTuple.first, VPos.TOP);
GridPane.setMargin(cryptoCurrenciesTuple.first, new Insets(0, 0, 0, 20));
cryptoCurrenciesListView = cryptoCurrenciesTuple.second;
GridPane.setColumnIndex(cryptoCurrenciesTuple.first, 2);
GridPane.setColumnIndex(cryptoCurrenciesListView, 3);
cryptoCurrenciesListView.setMinHeight(2 * Layout.LIST_ROW_HEIGHT + 2);
cryptoCurrenciesListView.setMaxHeight(6 * Layout.LIST_ROW_HEIGHT + 2);
placeholder = new Label("There are no crypto currencies selected");
placeholder.setWrapText(true);
cryptoCurrenciesListView.setPlaceholder(placeholder);
cryptoCurrenciesListView.setCellFactory(new Callback<ListView<CryptoCurrency>, ListCell<CryptoCurrency>>() {
@Override
public ListCell<CryptoCurrency> call(ListView<CryptoCurrency> list) {
return new ListCell<CryptoCurrency>() {
final Label label = new Label();
final ImageView icon = ImageUtil.getImageViewById(ImageUtil.REMOVE_ICON);
final Button removeButton = new Button("", icon);
final AnchorPane pane = new AnchorPane(label, removeButton);
{
label.setLayoutY(5);
removeButton.setId("icon-button");
AnchorPane.setRightAnchor(removeButton, 0d);
}
@Override
public void updateItem(final CryptoCurrency item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
label.setText(item.getNameAndCode());
removeButton.setOnAction(e -> {
if (item.equals(preferences.getPreferredTradeCurrency())) {
new Popup().warning("You cannot remove your selected preferred display currency").show();
} else {
preferences.removeCryptoCurrency(item);
if (!allCryptoCurrencies.contains(item))
allCryptoCurrencies.add(item);
}
});
setGraphic(pane);
} else {
setGraphic(null);
removeButton.setOnAction(null);
}
}
};
}
});
fiatCurrenciesComboBox = addLabelComboBox(root, ++gridRow).second;
fiatCurrenciesComboBox.setPromptText("Add national currency");
fiatCurrenciesComboBox.setConverter(new StringConverter<FiatCurrency>() {
@Override
public String toString(FiatCurrency tradeCurrency) {
return tradeCurrency.getNameAndCode();
}
@Override
public FiatCurrency fromString(String s) {
return null;
}
});
Tuple2<Label, ComboBox> labelComboBoxTuple2 = addLabelComboBox(root, gridRow);
cryptoCurrenciesComboBox = labelComboBoxTuple2.second;
GridPane.setColumnIndex(cryptoCurrenciesComboBox, 3);
cryptoCurrenciesComboBox.setPromptText("Add crypto currency");
cryptoCurrenciesComboBox.setConverter(new StringConverter<CryptoCurrency>() {
@Override
public String toString(CryptoCurrency tradeCurrency) {
return tradeCurrency.getNameAndCode();
}
@Override
public CryptoCurrency fromString(String s) {
return null;
}
});
}
private void initializeOtherOptions() {
TitledGroupBg titledGroupBg = addTitledGroupBg(root, ++gridRow, 3, "Options", Layout.GROUP_DISTANCE);
GridPane.setColumnSpan(titledGroupBg, 4);
userLanguageComboBox = addLabelComboBox(root, gridRow, "Language:", Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
// btcDenominationComboBox = addLabelComboBox(root, ++gridRow, "Bitcoin denomination:").second;
blockChainExplorerComboBox = addLabelComboBox(root, ++gridRow, "Bitcoin block explorer:").second;
autoSelectArbitratorsCheckBox = addLabelCheckBox(root, ++gridRow, "Auto select arbitrators:", "").second;
// TODO need a bit extra work to separate trade and non trade tx fees before it can be used
/*transactionFeeInputTextField = addLabelInputTextField(root, ++gridRow, "Transaction fee (satoshi/byte):").second;
transactionFeeFocusedListener = (o, oldValue, newValue) -> {
onFocusOutTransactionFeeTextField(oldValue, newValue);
};*/
}
private void initializeDisplayOptions() {
TitledGroupBg titledGroupBg = addTitledGroupBg(root, ++gridRow, 4, "Display options", Layout.GROUP_DISTANCE);
GridPane.setColumnSpan(titledGroupBg, 4);
useAnimationsCheckBox = addLabelCheckBox(root, gridRow, "Use animations:", "", Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
Tuple2<Label, CheckBox> labelCheckBoxTuple2 = addLabelCheckBox(root, gridRow, "Show notifications:", "", Layout.FIRST_ROW_AND_GROUP_DISTANCE);
showNotificationsCheckBox = labelCheckBoxTuple2.second;
GridPane.setColumnIndex(labelCheckBoxTuple2.first, 2);
GridPane.setColumnIndex(showNotificationsCheckBox, 3);
useEffectsCheckBox = addLabelCheckBox(root, ++gridRow, "Use effects:", "").second;
labelCheckBoxTuple2 = addLabelCheckBox(root, gridRow, "Show instruction popups:", "");
showInstructionsCheckBox = labelCheckBoxTuple2.second;
GridPane.setColumnIndex(labelCheckBoxTuple2.first, 2);
GridPane.setColumnIndex(showInstructionsCheckBox, 3);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Activate
///////////////////////////////////////////////////////////////////////////////////////////
private void activateDisplayCurrencies() {
preferredTradeCurrencyComboBox.setItems(tradeCurrencies);
preferredTradeCurrencyComboBox.getSelectionModel().select(preferences.getPreferredTradeCurrency());
preferredTradeCurrencyComboBox.setOnAction(e -> {
TradeCurrency selectedItem = preferredTradeCurrencyComboBox.getSelectionModel().getSelectedItem();
if (selectedItem != null)
preferences.setPreferredTradeCurrency(selectedItem);
});
fiatCurrenciesComboBox.setItems(allFiatCurrencies);
fiatCurrenciesListView.setItems(fiatCurrencies);
fiatCurrenciesComboBox.setOnAction(e -> {
FiatCurrency selectedItem = fiatCurrenciesComboBox.getSelectionModel().getSelectedItem();
log.error("setOnAction " + selectedItem);
if (selectedItem != null) {
preferences.addFiatCurrency(selectedItem);
if (allFiatCurrencies.contains(selectedItem)) {
UserThread.execute(() -> {
fiatCurrenciesComboBox.getSelectionModel().clearSelection();
allFiatCurrencies.remove(selectedItem);
});
}
}
});
cryptoCurrenciesComboBox.setItems(allCryptoCurrencies);
cryptoCurrenciesListView.setItems(cryptoCurrencies);
cryptoCurrenciesComboBox.setOnAction(e -> {
CryptoCurrency selectedItem = cryptoCurrenciesComboBox.getSelectionModel().getSelectedItem();
if (selectedItem != null) {
preferences.addCryptoCurrency(selectedItem);
if (allCryptoCurrencies.contains(selectedItem)) {
UserThread.execute(() -> {
cryptoCurrenciesComboBox.getSelectionModel().clearSelection();
allCryptoCurrencies.remove(selectedItem);
});
}
}
});
}
private void activateOtherOptions() {
transactionFeePerByte.set(String.valueOf(preferences.getTxFeePerKB() / 1000));
/* btcDenominationComboBox.setDisable(true);
btcDenominationComboBox.setItems(btcDenominations);
btcDenominationComboBox.getSelectionModel().select(getBtcDenomination());
btcDenominationComboBox.setOnAction(e -> onSelectBtcDenomination(btcDenominationComboBox.getSelectionModel().getSelectedItem()));*/
userLanguageComboBox.setItems(languageCodes);
userLanguageComboBox.getSelectionModel().select(preferences.getPreferredLocale().getLanguage());
userLanguageComboBox.setConverter(new StringConverter<String>() {
@Override
public String toString(String code) {
return LanguageUtil.getDisplayName(code);
@ -113,10 +373,13 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
return null;
}
});
languageComboBox.setOnAction(e -> model.onSelectLanguageCode(languageComboBox.getSelectionModel().getSelectedItem()));
userLanguageComboBox.setOnAction(e -> {
String code = userLanguageComboBox.getSelectionModel().getSelectedItem();
preferences.setPreferredLocale(new Locale(code, preferences.getPreferredLocale().getCountry()));
});
blockChainExplorerComboBox.setItems(model.blockExplorers);
blockChainExplorerComboBox.setItems(blockExplorers);
blockChainExplorerComboBox.getSelectionModel().select(preferences.getBlockChainExplorer());
blockChainExplorerComboBox.setConverter(new StringConverter<BlockChainExplorer>() {
@Override
@ -131,9 +394,11 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
});
blockChainExplorerComboBox.setOnAction(e -> preferences.setBlockChainExplorer(blockChainExplorerComboBox.getSelectionModel().getSelectedItem()));
// transactionFeeInputTextField.textProperty().bindBidirectional(model.transactionFeePerByte);
// transactionFeeInputTextField.textProperty().bindBidirectional(transactionFeePerByte);
// transactionFeeInputTextField.focusedProperty().addListener(transactionFeeFocusedListener);
}
private void activateDisplayPreferences() {
useAnimationsCheckBox.setSelected(preferences.getUseAnimations());
useAnimationsCheckBox.setOnAction(e -> preferences.setUseAnimations(useAnimationsCheckBox.isSelected()));
@ -150,18 +415,30 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
autoSelectArbitratorsCheckBox.setOnAction(e -> preferences.setAutoSelectArbitrators(autoSelectArbitratorsCheckBox.isSelected()));
}
@Override
protected void deactivate() {
//btcDenominationComboBox.setOnAction(null);
languageComboBox.setOnAction(null);
///////////////////////////////////////////////////////////////////////////////////////////
// Deactivate
///////////////////////////////////////////////////////////////////////////////////////////
private void deactivateDisplayCurrencies() {
preferredTradeCurrencyComboBox.setOnAction(null);
}
private void deactivateOtherOptions() {
//btcDenominationComboBox.setOnAction(null);
userLanguageComboBox.setOnAction(null);
blockChainExplorerComboBox.setOnAction(null);
showNotificationsCheckBox.setOnAction(null);
showInstructionsCheckBox.setOnAction(null);
// transactionFeeInputTextField.textProperty().unbind();
/// transactionFeeInputTextField.focusedProperty().removeListener(transactionFeeFocusedListener);
}
private void deactivateDisplayPreferences() {
useAnimationsCheckBox.setOnAction(null);
useEffectsCheckBox.setOnAction(null);
autoSelectArbitratorsCheckBox.setOnAction(null);
}
}

View File

@ -1,100 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.settings.preferences;
import com.google.inject.Inject;
import io.bitsquare.common.UserThread;
import io.bitsquare.gui.common.model.ActivatableViewModel;
import io.bitsquare.gui.main.popups.Popup;
import io.bitsquare.locale.LanguageUtil;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.user.BlockChainExplorer;
import io.bitsquare.user.Preferences;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
class PreferencesViewModel extends ActivatableViewModel {
private final Preferences preferences;
final ObservableList<String> btcDenominations = FXCollections.observableArrayList(Preferences.getBtcDenominations());
final ObservableList<BlockChainExplorer> blockExplorers;
final ObservableList<TradeCurrency> tradeCurrencies;
final ObservableList<String> languageCodes;
final StringProperty transactionFeePerByte = new SimpleStringProperty();
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialisation
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public PreferencesViewModel(Preferences preferences) {
this.preferences = preferences;
blockExplorers = FXCollections.observableArrayList(preferences.getBlockChainExplorers());
tradeCurrencies = preferences.getTradeCurrenciesAsObservable();
languageCodes = FXCollections.observableArrayList(LanguageUtil.getAllLanguageCodes());
}
@Override
protected void activate() {
transactionFeePerByte.set(String.valueOf(preferences.getTxFeePerKB() / 1000));
}
@Override
protected void deactivate() {
}
///////////////////////////////////////////////////////////////////////////////////////////
// UI actions
///////////////////////////////////////////////////////////////////////////////////////////
public void onSelectLanguageCode(String code) {
preferences.setPreferredLocale(new Locale(code, preferences.getPreferredLocale().getCountry()));
}
public void onFocusOutTransactionFeeTextField(Boolean oldValue, Boolean newValue) {
if (oldValue && !newValue) {
try {
preferences.setTxFeePerKB(Long.parseLong(transactionFeePerByte.get()) * 1000);
} catch (Exception e) {
log.warn("Error at onFocusOutTransactionFeeTextField: " + e.getMessage());
new Popup().warning(e.getMessage())
.onClose(() -> UserThread.runAfter(
() -> transactionFeePerByte.set(String.valueOf(preferences.getTxFeePerKB() / 1000)),
100, TimeUnit.MILLISECONDS))
.show();
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public String getLanguageCode() {
return preferences.getPreferredLocale().getLanguage();
}
}

View File

@ -153,3 +153,16 @@ SWISH= Swish
TRANSFER_WISE=TransferWise
US_POSTAL_MONEY_ORDER=US Postal money order
BLOCK_CHAINS=Crypto currencies
OK_PAY_SHORT=OKPay
PERFECT_MONEY_SHORT=Perfect Money
ALI_PAY_SHORT=AliPay
SEPA_SHORT=SEPA
NATIONAL_BANK_SHORT=National Banks
SAME_BANK_SHORT=Same Bank
SPECIFIC_BANKS_SHORT=Specific banks
FED_WIRE_SHORT=Fed Wire
SWISH_SHORT= Swish
TRANSFER_WISE_SHORT=TransferWise
US_POSTAL_MONEY_ORDER_SHORT=Money order
BLOCK_CHAINS_SHORT=Crypto currencies

View File

@ -190,9 +190,6 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
if (result) {
map.put(hashOfPayload, protectedStorageEntry);
sequenceNumberMap.put(hashOfPayload, new MapValue(protectedStorageEntry.sequenceNumber, System.currentTimeMillis()));
storage.queueUpForSave(sequenceNumberMap, 100);
StringBuilder sb = new StringBuilder("\n\n------------------------------------------------------------\n");
sb.append("Data set after doAdd (truncated)");
map.values().stream().forEach(e -> sb.append("\n").append(StringUtils.abbreviate(e.toString(), 100)));
@ -200,8 +197,13 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
log.trace(sb.toString());
log.info("Data set after doAdd: size=" + map.values().size());
broadcast(new AddDataMessage(protectedStorageEntry), sender, listener, isDataOwner);
if (hasSequenceNrIncreased(protectedStorageEntry.sequenceNumber, hashOfPayload)) {
sequenceNumberMap.put(hashOfPayload, new MapValue(protectedStorageEntry.sequenceNumber, System.currentTimeMillis()));
storage.queueUpForSave(sequenceNumberMap, 100);
broadcast(new AddDataMessage(protectedStorageEntry), sender, listener, isDataOwner);
}
hashMapChangedListeners.stream().forEach(e -> e.onAdded(protectedStorageEntry));
} else {
log.trace("add failed");
@ -226,7 +228,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
} else {
PublicKey ownerPubKey = storedData.getStoragePayload().getOwnerPubKey();
boolean result = checkSignature(ownerPubKey, hashOfDataAndSeqNr, signature) &&
isSequenceNrValid(sequenceNumber, hashOfPayload) &&
hasSequenceNrIncreased(sequenceNumber, hashOfPayload) &&
checkIfStoredDataPubKeyMatchesNewDataPubKey(ownerPubKey, hashOfPayload);
if (result) {
@ -381,6 +383,22 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
}
private boolean isSequenceNrValid(int newSequenceNumber, ByteArray hashOfData) {
if (sequenceNumberMap.containsKey(hashOfData)) {
Integer storedSequenceNumber = sequenceNumberMap.get(hashOfData).sequenceNr;
if (newSequenceNumber >= storedSequenceNumber) {
return true;
} else {
log.info("Sequence number is invalid. sequenceNumber = "
+ newSequenceNumber + " / storedSequenceNumber=" + storedSequenceNumber + "\n" +
"That can happen if the data owner gets an old delayed data storage message.");
return false;
}
} else {
return true;
}
}
private boolean hasSequenceNrIncreased(int newSequenceNumber, ByteArray hashOfData) {
if (sequenceNumberMap.containsKey(hashOfData)) {
Integer storedSequenceNumber = sequenceNumberMap.get(hashOfData).sequenceNr;
if (newSequenceNumber > storedSequenceNumber) {