mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
fiat currency support
This commit is contained in:
parent
539013919b
commit
c477d31d3d
14 changed files with 619 additions and 15 deletions
|
@ -52,6 +52,10 @@ public class AppController implements Initializable {
|
|||
private static final int SERVER_PING_PERIOD = 10 * 1000;
|
||||
private static final int ENUMERATE_HW_PERIOD = 30 * 1000;
|
||||
|
||||
private static final int RATES_PERIOD = 5 * 60 * 1000;
|
||||
private static final ExchangeSource DEFAULT_EXCHANGE_SOURCE = ExchangeSource.COINGECKO;
|
||||
private static final Currency DEFAULT_FIAT_CURRENCY = Currency.getInstance("USD");
|
||||
|
||||
public static final String DRAG_OVER_CLASS = "drag-over";
|
||||
|
||||
private MainApp application;
|
||||
|
@ -90,6 +94,8 @@ public class AppController implements Initializable {
|
|||
|
||||
private Timeline statusTimeline;
|
||||
|
||||
private ExchangeSource.RatesService ratesService;
|
||||
|
||||
private ElectrumServer.ConnectionService connectionService;
|
||||
|
||||
private static Integer currentBlockHeight;
|
||||
|
@ -98,6 +104,8 @@ public class AppController implements Initializable {
|
|||
|
||||
private static Map<Integer, Double> targetBlockFeeRates;
|
||||
|
||||
private static Map<Currency, Double> fiatCurrencyExchangeRate;
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
EventManager.get().register(this);
|
||||
|
@ -174,20 +182,36 @@ public class AppController implements Initializable {
|
|||
if(!connectionService.isRunning()) {
|
||||
connectionService.start();
|
||||
}
|
||||
|
||||
if(ratesService.getState() == Worker.State.CANCELLED) {
|
||||
ratesService.reset();
|
||||
}
|
||||
|
||||
if(!ratesService.isRunning() && ratesService.getExchangeSource() != ExchangeSource.NONE) {
|
||||
ratesService.start();
|
||||
}
|
||||
} else {
|
||||
connectionService.cancel();
|
||||
ratesService.cancel();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
onlineProperty.bindBidirectional(serverToggle.selectedProperty());
|
||||
|
||||
connectionService = createConnectionService();
|
||||
Config config = Config.get();
|
||||
connectionService = createConnectionService();
|
||||
if(config.getMode() == Mode.ONLINE && config.getElectrumServer() != null && !config.getElectrumServer().isEmpty()) {
|
||||
connectionService.start();
|
||||
}
|
||||
|
||||
ExchangeSource source = config.getExchangeSource() != null ? config.getExchangeSource() : DEFAULT_EXCHANGE_SOURCE;
|
||||
Currency currency = config.getFiatCurrency() != null ? config.getFiatCurrency() : DEFAULT_FIAT_CURRENCY;
|
||||
ratesService = createRatesService(source, currency);
|
||||
if (config.getMode() == Mode.ONLINE && source != ExchangeSource.NONE) {
|
||||
ratesService.start();
|
||||
}
|
||||
|
||||
openTransactionIdItem.disableProperty().bind(onlineProperty.not());
|
||||
|
||||
openWalletFile(new File("/Users/scy/.sparrow/wallets/sparta.json"));
|
||||
|
@ -219,6 +243,18 @@ public class AppController implements Initializable {
|
|||
return connectionService;
|
||||
}
|
||||
|
||||
private ExchangeSource.RatesService createRatesService(ExchangeSource exchangeSource, Currency currency) {
|
||||
ExchangeSource.RatesService ratesService = new ExchangeSource.RatesService(exchangeSource, currency);
|
||||
ratesService.setPeriod(new Duration(RATES_PERIOD));
|
||||
ratesService.setRestartOnFailure(true);
|
||||
|
||||
ratesService.setOnSucceeded(successEvent -> {
|
||||
EventManager.get().post(ratesService.getValue());
|
||||
});
|
||||
|
||||
return ratesService;
|
||||
}
|
||||
|
||||
public void setApplication(MainApp application) {
|
||||
this.application = application;
|
||||
}
|
||||
|
@ -361,6 +397,10 @@ public class AppController implements Initializable {
|
|||
return targetBlockFeeRates;
|
||||
}
|
||||
|
||||
public static Map<Currency, Double> getFiatCurrencyExchangeRate() {
|
||||
return fiatCurrencyExchangeRate;
|
||||
}
|
||||
|
||||
public static void showErrorDialog(String title, String content) {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setTitle(title);
|
||||
|
@ -820,4 +860,25 @@ public class AppController implements Initializable {
|
|||
Tab tab = addTransactionTab(event.getBlockTransaction(), event.getInitialView(), event.getInitialIndex());
|
||||
tabs.getSelectionModel().select(tab);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) {
|
||||
Optional<Toggle> selectedToggle = bitcoinUnit.getToggles().stream().filter(toggle -> event.getBitcoinUnit().equals(toggle.getUserData())).findFirst();
|
||||
selectedToggle.ifPresent(toggle -> bitcoinUnit.selectToggle(toggle));
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void fiatCurrencySelected(FiatCurrencySelectedEvent event) {
|
||||
ratesService.cancel();
|
||||
|
||||
if (Config.get().getMode() != Mode.OFFLINE && event.getExchangeSource() != ExchangeSource.NONE) {
|
||||
ratesService = createRatesService(event.getExchangeSource(), event.getCurrency());
|
||||
ratesService.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void exchangeRatesUpdated(ExchangeRatesUpdatedEvent event) {
|
||||
fiatCurrencyExchangeRate = Map.of(event.getSelectedCurrency(), event.getRate());
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ import java.util.Locale;
|
|||
public class CoinLabel extends CopyableLabel {
|
||||
public static final DecimalFormat BTC_FORMAT = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
|
||||
|
||||
private final LongProperty value = new SimpleLongProperty(-1);
|
||||
private final LongProperty valueProperty = new SimpleLongProperty(-1);
|
||||
private final Tooltip tooltip;
|
||||
private final CoinContextMenu contextMenu;
|
||||
|
||||
|
@ -35,15 +35,15 @@ public class CoinLabel extends CopyableLabel {
|
|||
}
|
||||
|
||||
public final LongProperty valueProperty() {
|
||||
return value;
|
||||
return valueProperty;
|
||||
}
|
||||
|
||||
public final long getValue() {
|
||||
return value.get();
|
||||
return valueProperty.get();
|
||||
}
|
||||
|
||||
public final void setValue(long value) {
|
||||
this.value.set(value);
|
||||
this.valueProperty.set(value);
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
|
|
120
src/main/java/com/sparrowwallet/sparrow/control/FiatLabel.java
Normal file
120
src/main/java/com/sparrowwallet/sparrow/control/FiatLabel.java
Normal file
|
@ -0,0 +1,120 @@
|
|||
package com.sparrowwallet.sparrow.control;
|
||||
|
||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.input.Clipboard;
|
||||
import javafx.scene.input.ClipboardContent;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Currency;
|
||||
|
||||
public class FiatLabel extends CopyableLabel {
|
||||
private static final DecimalFormat CURRENCY_FORMAT = new DecimalFormat("#,##0.00");
|
||||
|
||||
private final LongProperty valueProperty = new SimpleLongProperty(-1);
|
||||
private final DoubleProperty btcRateProperty = new SimpleDoubleProperty(0.0);
|
||||
private final ObjectProperty<Currency> currencyProperty = new SimpleObjectProperty<>(null);
|
||||
private final Tooltip tooltip;
|
||||
private final FiatContextMenu contextMenu;
|
||||
|
||||
public FiatLabel() {
|
||||
this("");
|
||||
}
|
||||
|
||||
public FiatLabel(String text) {
|
||||
super(text);
|
||||
valueProperty().addListener((observable, oldValue, newValue) -> setValueAsText((Long)newValue));
|
||||
btcRateProperty().addListener((observable, oldValue, newValue) -> setValueAsText(getValue()));
|
||||
currencyProperty().addListener((observable, oldValue, newValue) -> setValueAsText(getValue()));
|
||||
tooltip = new Tooltip();
|
||||
contextMenu = new FiatContextMenu();
|
||||
}
|
||||
|
||||
public final LongProperty valueProperty() {
|
||||
return valueProperty;
|
||||
}
|
||||
|
||||
public final long getValue() {
|
||||
return valueProperty.get();
|
||||
}
|
||||
|
||||
public final void setValue(long value) {
|
||||
this.valueProperty.set(value);
|
||||
}
|
||||
|
||||
public final DoubleProperty btcRateProperty() {
|
||||
return btcRateProperty;
|
||||
}
|
||||
|
||||
public final double getBtcRate() {
|
||||
return btcRateProperty.get();
|
||||
}
|
||||
|
||||
public final void setBtcRate(double btcRate) {
|
||||
this.btcRateProperty.set(btcRate);
|
||||
}
|
||||
|
||||
public final ObjectProperty<Currency> currencyProperty() {
|
||||
return currencyProperty;
|
||||
}
|
||||
|
||||
public final Currency getCurrency() {
|
||||
return currencyProperty.get();
|
||||
}
|
||||
|
||||
public final void setCurrency(Currency currency) {
|
||||
this.currencyProperty.set(currency);
|
||||
}
|
||||
|
||||
public final void set(Currency currency, double btcRate, long value) {
|
||||
setValue(value);
|
||||
setBtcRate(btcRate);
|
||||
setCurrency(currency);
|
||||
}
|
||||
|
||||
private void setValueAsText(long balance) {
|
||||
if(getCurrency() != null && getBtcRate() > 0.0) {
|
||||
BigDecimal satsBalance = BigDecimal.valueOf(balance);
|
||||
BigDecimal btcBalance = satsBalance.divide(BigDecimal.valueOf(Transaction.SATOSHIS_PER_BITCOIN));
|
||||
BigDecimal fiatBalance = btcBalance.multiply(BigDecimal.valueOf(getBtcRate()));
|
||||
|
||||
DecimalFormat currencyFormat = new DecimalFormat("#,##0.00");
|
||||
String label = getCurrency().getSymbol() + " " + currencyFormat.format(fiatBalance.doubleValue());
|
||||
tooltip.setText("1 BTC = " + getCurrency().getSymbol() + " " + currencyFormat.format(getBtcRate()));
|
||||
|
||||
setText(label);
|
||||
setTooltip(tooltip);
|
||||
setContextMenu(contextMenu);
|
||||
} else {
|
||||
setText("");
|
||||
setTooltip(null);
|
||||
setContextMenu(null);
|
||||
}
|
||||
}
|
||||
|
||||
private class FiatContextMenu extends ContextMenu {
|
||||
public FiatContextMenu() {
|
||||
MenuItem copyValue = new MenuItem("Copy Value");
|
||||
copyValue.setOnAction(AE -> {
|
||||
hide();
|
||||
ClipboardContent content = new ClipboardContent();
|
||||
content.putString(getText());
|
||||
Clipboard.getSystemClipboard().setContent(content);
|
||||
});
|
||||
|
||||
MenuItem copyRate = new MenuItem("Copy Rate");
|
||||
copyRate.setOnAction(AE -> {
|
||||
hide();
|
||||
ClipboardContent content = new ClipboardContent();
|
||||
content.putString(getTooltip().getText());
|
||||
Clipboard.getSystemClipboard().setContent(content);
|
||||
});
|
||||
|
||||
getItems().addAll(copyValue, copyRate);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.sparrowwallet.sparrow.event;
|
||||
|
||||
import java.util.Currency;
|
||||
|
||||
public class ExchangeRatesUpdatedEvent {
|
||||
private final Currency selectedCurrency;
|
||||
private final Double rate;
|
||||
|
||||
public ExchangeRatesUpdatedEvent(Currency selectedCurrency, Double rate) {
|
||||
this.selectedCurrency = selectedCurrency;
|
||||
this.rate = rate;
|
||||
}
|
||||
|
||||
public Currency getSelectedCurrency() {
|
||||
return selectedCurrency;
|
||||
}
|
||||
|
||||
public Double getRate() {
|
||||
return rate;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.sparrowwallet.sparrow.event;
|
||||
|
||||
import com.sparrowwallet.sparrow.io.ExchangeSource;
|
||||
|
||||
import java.util.Currency;
|
||||
|
||||
public class FiatCurrencySelectedEvent {
|
||||
private final ExchangeSource exchangeSource;
|
||||
private final Currency currency;
|
||||
|
||||
public FiatCurrencySelectedEvent(ExchangeSource exchangeSource, Currency currency) {
|
||||
this.exchangeSource = exchangeSource;
|
||||
this.currency = currency;
|
||||
}
|
||||
|
||||
public ExchangeSource getExchangeSource() {
|
||||
return exchangeSource;
|
||||
}
|
||||
|
||||
public Currency getCurrency() {
|
||||
return currency;
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ public class FontAwesome5 extends GlyphFont {
|
|||
QUESTION_CIRCLE('\uf059'),
|
||||
SD_CARD('\uf7c2'),
|
||||
SEARCH('\uf002'),
|
||||
TOOLS('\uf7d9'),
|
||||
WALLET('\uf555');
|
||||
|
||||
private final char ch;
|
||||
|
|
|
@ -6,12 +6,15 @@ import com.sparrowwallet.sparrow.Mode;
|
|||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Currency;
|
||||
|
||||
public class Config {
|
||||
public static final String CONFIG_FILENAME = ".config";
|
||||
|
||||
private Mode mode;
|
||||
private BitcoinUnit bitcoinUnit;
|
||||
private Currency fiatCurrency;
|
||||
private ExchangeSource exchangeSource;
|
||||
private Integer keyDerivationPeriod;
|
||||
private File hwi;
|
||||
private String electrumServer;
|
||||
|
@ -78,6 +81,24 @@ public class Config {
|
|||
flush();
|
||||
}
|
||||
|
||||
public Currency getFiatCurrency() {
|
||||
return fiatCurrency;
|
||||
}
|
||||
|
||||
public void setFiatCurrency(Currency fiatCurrency) {
|
||||
this.fiatCurrency = fiatCurrency;
|
||||
flush();
|
||||
}
|
||||
|
||||
public ExchangeSource getExchangeSource() {
|
||||
return exchangeSource;
|
||||
}
|
||||
|
||||
public void setExchangeSource(ExchangeSource exchangeSource) {
|
||||
this.exchangeSource = exchangeSource;
|
||||
flush();
|
||||
}
|
||||
|
||||
public Integer getKeyDerivationPeriod() {
|
||||
return keyDerivationPeriod;
|
||||
}
|
||||
|
|
171
src/main/java/com/sparrowwallet/sparrow/io/ExchangeSource.java
Normal file
171
src/main/java/com/sparrowwallet/sparrow/io/ExchangeSource.java
Normal file
|
@ -0,0 +1,171 @@
|
|||
package com.sparrowwallet.sparrow.io;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.sparrowwallet.sparrow.event.ExchangeRatesUpdatedEvent;
|
||||
import javafx.concurrent.ScheduledService;
|
||||
import javafx.concurrent.Service;
|
||||
import javafx.concurrent.Task;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public enum ExchangeSource {
|
||||
NONE("None") {
|
||||
@Override
|
||||
public List<Currency> getSupportedCurrencies() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getExchangeRate(Currency currency) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
COINBASE("Coinbase") {
|
||||
@Override
|
||||
public List<Currency> getSupportedCurrencies() {
|
||||
return getRates().data.rates.keySet().stream().filter(code -> isValidISO4217Code(code.toUpperCase()))
|
||||
.map(code -> Currency.getInstance(code.toUpperCase())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getExchangeRate(Currency currency) {
|
||||
String currencyCode = currency.getCurrencyCode();
|
||||
OptionalDouble optRate = getRates().data.rates.entrySet().stream().filter(rate -> currencyCode.equalsIgnoreCase(rate.getKey())).mapToDouble(Map.Entry::getValue).findFirst();
|
||||
if(optRate.isPresent()) {
|
||||
return optRate.getAsDouble();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private CoinbaseRates getRates() {
|
||||
String url = "https://api.coinbase.com/v2/exchange-rates?currency=BTC";
|
||||
|
||||
try(InputStream is = new URL(url).openStream(); Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
|
||||
Gson gson = new Gson();
|
||||
return gson.fromJson(reader, CoinbaseRates.class);
|
||||
} catch (Exception e) {
|
||||
return new CoinbaseRates();
|
||||
}
|
||||
}
|
||||
},
|
||||
COINGECKO("Coingecko") {
|
||||
@Override
|
||||
public List<Currency> getSupportedCurrencies() {
|
||||
return getRates().rates.entrySet().stream().filter(rate -> "fiat".equals(rate.getValue().type) && isValidISO4217Code(rate.getKey().toUpperCase()))
|
||||
.map(rate -> Currency.getInstance(rate.getKey().toUpperCase())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getExchangeRate(Currency currency) {
|
||||
String currencyCode = currency.getCurrencyCode();
|
||||
OptionalDouble optRate = getRates().rates.entrySet().stream().filter(rate -> currencyCode.equalsIgnoreCase(rate.getKey())).mapToDouble(rate -> rate.getValue().value).findFirst();
|
||||
if(optRate.isPresent()) {
|
||||
return optRate.getAsDouble();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private CoinGeckoRates getRates() {
|
||||
String url = "https://api.coingecko.com/api/v3/exchange_rates";
|
||||
|
||||
try(InputStream is = new URL(url).openStream(); Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
|
||||
Gson gson = new Gson();
|
||||
return gson.fromJson(reader, CoinGeckoRates.class);
|
||||
} catch (Exception e) {
|
||||
return new CoinGeckoRates();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final String name;
|
||||
|
||||
ExchangeSource(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public abstract List<Currency> getSupportedCurrencies();
|
||||
|
||||
public abstract Double getExchangeRate(Currency currency);
|
||||
|
||||
private static boolean isValidISO4217Code(String code) {
|
||||
try {
|
||||
Currency currency = Currency.getInstance(code);
|
||||
return true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static class CurrenciesService extends Service<List<Currency>> {
|
||||
private final ExchangeSource exchangeSource;
|
||||
|
||||
public CurrenciesService(ExchangeSource exchangeSource) {
|
||||
this.exchangeSource = exchangeSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Task<List<Currency>> createTask() {
|
||||
return new Task<>() {
|
||||
protected List<Currency> call() {
|
||||
return exchangeSource.getSupportedCurrencies();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class RatesService extends ScheduledService<ExchangeRatesUpdatedEvent> {
|
||||
private final ExchangeSource exchangeSource;
|
||||
private final Currency selectedCurrency;
|
||||
|
||||
public RatesService(ExchangeSource exchangeSource, Currency selectedCurrency) {
|
||||
this.exchangeSource = exchangeSource;
|
||||
this.selectedCurrency = selectedCurrency;
|
||||
}
|
||||
|
||||
protected Task<ExchangeRatesUpdatedEvent> createTask() {
|
||||
return new Task<>() {
|
||||
protected ExchangeRatesUpdatedEvent call() {
|
||||
Double rate = exchangeSource.getExchangeRate(selectedCurrency);
|
||||
return new ExchangeRatesUpdatedEvent(selectedCurrency, rate);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public ExchangeSource getExchangeSource() {
|
||||
return exchangeSource;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CoinbaseRates {
|
||||
CoinbaseData data;
|
||||
}
|
||||
|
||||
private static class CoinbaseData {
|
||||
String currency;
|
||||
Map<String, Double> rates;
|
||||
}
|
||||
|
||||
private static class CoinGeckoRates {
|
||||
Map<String, CoinGeckoRate> rates = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
private static class CoinGeckoRate {
|
||||
String name;
|
||||
String unit;
|
||||
Double value;
|
||||
String type;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package com.sparrowwallet.sparrow.preferences;
|
||||
|
||||
import com.sparrowwallet.drongo.BitcoinUnit;
|
||||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.event.BitcoinUnitChangedEvent;
|
||||
import com.sparrowwallet.sparrow.event.FiatCurrencySelectedEvent;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import com.sparrowwallet.sparrow.io.ExchangeSource;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.ComboBox;
|
||||
|
||||
import java.util.Currency;
|
||||
import java.util.List;
|
||||
|
||||
public class GeneralPreferencesController extends PreferencesDetailController {
|
||||
@FXML
|
||||
private ComboBox<BitcoinUnit> bitcoinUnit;
|
||||
|
||||
@FXML
|
||||
private ComboBox<Currency> fiatCurrency;
|
||||
|
||||
@FXML
|
||||
private ComboBox<ExchangeSource> exchangeSource;
|
||||
|
||||
private final ChangeListener<Currency> fiatCurrencyListener = new ChangeListener<Currency>() {
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends Currency> observable, Currency oldValue, Currency newValue) {
|
||||
if (newValue != null) {
|
||||
Config.get().setFiatCurrency(newValue);
|
||||
EventManager.get().post(new FiatCurrencySelectedEvent(exchangeSource.getValue(), newValue));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void initializeView(Config config) {
|
||||
if(config.getBitcoinUnit() != null) {
|
||||
bitcoinUnit.setValue(config.getBitcoinUnit());
|
||||
}
|
||||
|
||||
bitcoinUnit.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
config.setBitcoinUnit(newValue);
|
||||
EventManager.get().post(new BitcoinUnitChangedEvent(newValue));
|
||||
});
|
||||
|
||||
if(config.getExchangeSource() != null) {
|
||||
exchangeSource.setValue(config.getExchangeSource());
|
||||
} else {
|
||||
exchangeSource.getSelectionModel().select(2);
|
||||
config.setExchangeSource(exchangeSource.getValue());
|
||||
}
|
||||
|
||||
exchangeSource.valueProperty().addListener((observable, oldValue, source) -> {
|
||||
config.setExchangeSource(source);
|
||||
updateCurrencies(source);
|
||||
});
|
||||
|
||||
updateCurrencies(exchangeSource.getSelectionModel().getSelectedItem());
|
||||
}
|
||||
|
||||
private void updateCurrencies(ExchangeSource exchangeSource) {
|
||||
ExchangeSource.CurrenciesService currenciesService = new ExchangeSource.CurrenciesService(exchangeSource);
|
||||
currenciesService.setOnSucceeded(event -> {
|
||||
updateCurrencies(currenciesService.getValue());
|
||||
});
|
||||
currenciesService.start();
|
||||
}
|
||||
|
||||
private void updateCurrencies(List<Currency> currencies) {
|
||||
fiatCurrency.valueProperty().removeListener(fiatCurrencyListener);
|
||||
|
||||
fiatCurrency.getItems().clear();
|
||||
fiatCurrency.getItems().addAll(currencies);
|
||||
|
||||
Currency configCurrency = Config.get().getFiatCurrency();
|
||||
if(configCurrency != null && currencies.contains(configCurrency)) {
|
||||
fiatCurrency.setDisable(false);
|
||||
fiatCurrency.setValue(configCurrency);
|
||||
} else if(!currencies.isEmpty()) {
|
||||
fiatCurrency.setDisable(false);
|
||||
fiatCurrency.getSelectionModel().select(0);
|
||||
Config.get().setFiatCurrency(fiatCurrency.getValue());
|
||||
} else {
|
||||
fiatCurrency.setDisable(true);
|
||||
}
|
||||
|
||||
//Always fire event regardless of previous selection to update rates
|
||||
EventManager.get().post(new FiatCurrencySelectedEvent(exchangeSource.getValue(), fiatCurrency.getValue()));
|
||||
|
||||
fiatCurrency.valueProperty().addListener(fiatCurrencyListener);
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ public class PreferencesDialog extends Dialog<Void> {
|
|||
if(initialGroup != null) {
|
||||
preferencesController.selectGroup(initialGroup);
|
||||
} else {
|
||||
preferencesController.selectGroup(PreferenceGroup.SERVER);
|
||||
preferencesController.selectGroup(PreferenceGroup.GENERAL);
|
||||
}
|
||||
|
||||
final ButtonType closeButtonType = new javafx.scene.control.ButtonType("Close", ButtonBar.ButtonData.CANCEL_CLOSE);
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package com.sparrowwallet.sparrow.wallet;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.sparrowwallet.sparrow.AppController;
|
||||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.control.BalanceChart;
|
||||
import com.sparrowwallet.sparrow.control.CoinLabel;
|
||||
import com.sparrowwallet.sparrow.control.CopyableLabel;
|
||||
import com.sparrowwallet.sparrow.control.FiatLabel;
|
||||
import com.sparrowwallet.sparrow.control.TransactionsTreeTable;
|
||||
import com.sparrowwallet.sparrow.event.*;
|
||||
import com.sparrowwallet.sparrow.io.ExchangeSource;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
|
@ -14,6 +16,8 @@ import javafx.scene.control.TreeItem;
|
|||
import javafx.scene.input.MouseEvent;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Currency;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class TransactionsController extends WalletFormController implements Initializable {
|
||||
|
@ -22,7 +26,7 @@ public class TransactionsController extends WalletFormController implements Init
|
|||
private CoinLabel balance;
|
||||
|
||||
@FXML
|
||||
private CopyableLabel fiatBalance;
|
||||
private FiatLabel fiatBalance;
|
||||
|
||||
@FXML
|
||||
private CoinLabel mempoolBalance;
|
||||
|
@ -45,6 +49,7 @@ public class TransactionsController extends WalletFormController implements Init
|
|||
transactionsTable.initialize(walletTransactionsEntry);
|
||||
|
||||
balance.setValue(walletTransactionsEntry.getBalance());
|
||||
setFiatBalance(AppController.getFiatCurrencyExchangeRate(), walletTransactionsEntry.getBalance());
|
||||
mempoolBalance.setValue(walletTransactionsEntry.getMempoolBalance());
|
||||
balanceChart.initialize(walletTransactionsEntry);
|
||||
|
||||
|
@ -56,6 +61,16 @@ public class TransactionsController extends WalletFormController implements Init
|
|||
});
|
||||
}
|
||||
|
||||
private void setFiatBalance(Map<Currency, Double> fiatCurrencyExchangeRate, long balance) {
|
||||
if(fiatCurrencyExchangeRate != null && !fiatCurrencyExchangeRate.isEmpty()) {
|
||||
Currency currency = fiatCurrencyExchangeRate.keySet().iterator().next();
|
||||
Double rate = fiatCurrencyExchangeRate.get(currency);
|
||||
if(rate != null) {
|
||||
fiatBalance.set(currency, rate, balance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void walletNodesChanged(WalletNodesChangedEvent event) {
|
||||
if(event.getWallet().equals(walletForm.getWallet())) {
|
||||
|
@ -99,6 +114,20 @@ public class TransactionsController extends WalletFormController implements Init
|
|||
mempoolBalance.refresh(event.getBitcoinUnit());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void fiatCurrencySelected(FiatCurrencySelectedEvent event) {
|
||||
if(event.getExchangeSource() == ExchangeSource.NONE) {
|
||||
fiatBalance.setCurrency(null);
|
||||
fiatBalance.setBtcRate(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void exchangeRatesUpdated(ExchangeRatesUpdatedEvent event) {
|
||||
Map<Currency, Double> fiatRate = Map.of(event.getSelectedCurrency(), event.getRate());
|
||||
setFiatBalance(fiatRate, getWalletForm().getWalletTransactionsEntry().getBalance());
|
||||
}
|
||||
|
||||
//TODO: Remove
|
||||
public void advanceBlock(MouseEvent event) {
|
||||
Integer currentBlock = getWalletForm().getWallet().getStoredBlockHeight();
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import java.lang.*?>
|
||||
<?import java.util.*?>
|
||||
<?import javafx.scene.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<?import tornadofx.control.Form?>
|
||||
<?import tornadofx.control.Fieldset?>
|
||||
<?import tornadofx.control.Field?>
|
||||
<?import javafx.collections.FXCollections?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import com.sparrowwallet.drongo.BitcoinUnit?>
|
||||
<?import com.sparrowwallet.sparrow.io.ExchangeSource?>
|
||||
<GridPane hgap="10.0" vgap="10.0" stylesheets="@preferences.css, @../general.css" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sparrowwallet.sparrow.preferences.GeneralPreferencesController">
|
||||
<padding>
|
||||
<Insets left="25.0" right="25.0" top="25.0" />
|
||||
</padding>
|
||||
<columnConstraints>
|
||||
<ColumnConstraints percentWidth="100" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints />
|
||||
</rowConstraints>
|
||||
|
||||
<Form GridPane.columnIndex="0" GridPane.rowIndex="0">
|
||||
<Fieldset inputGrow="SOMETIMES" text="Bitcoin">
|
||||
<Field text="Unit:">
|
||||
<ComboBox fx:id="bitcoinUnit">
|
||||
<items>
|
||||
<FXCollections fx:factory="observableArrayList">
|
||||
<BitcoinUnit fx:constant="AUTO" />
|
||||
<BitcoinUnit fx:constant="BTC" />
|
||||
<BitcoinUnit fx:constant="SATOSHIS" />
|
||||
</FXCollections>
|
||||
</items>
|
||||
</ComboBox>
|
||||
</Field>
|
||||
</Fieldset>
|
||||
<Fieldset inputGrow="SOMETIMES" text="Fiat">
|
||||
<Field text="Currency:">
|
||||
<ComboBox fx:id="fiatCurrency" />
|
||||
</Field>
|
||||
<Field text="Source:">
|
||||
<ComboBox fx:id="exchangeSource">
|
||||
<items>
|
||||
<FXCollections fx:factory="observableArrayList">
|
||||
<ExchangeSource fx:constant="NONE" />
|
||||
<ExchangeSource fx:constant="COINBASE" />
|
||||
<ExchangeSource fx:constant="COINGECKO" />
|
||||
</FXCollections>
|
||||
</items>
|
||||
</ComboBox>
|
||||
</Field>
|
||||
</Fieldset>
|
||||
</Form>
|
||||
</GridPane>
|
|
@ -10,15 +10,20 @@
|
|||
<?import com.sparrowwallet.sparrow.preferences.PreferenceGroup?>
|
||||
<?import org.controlsfx.glyphfont.Glyph?>
|
||||
<BorderPane stylesheets="@../general.css, @preferences.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.preferences.PreferencesController">
|
||||
<padding>
|
||||
<Insets top="0" left="0" right="0" bottom="0" />
|
||||
</padding>
|
||||
<left>
|
||||
<VBox styleClass="list-menu">
|
||||
<ToggleButton VBox.vgrow="ALWAYS" text="Server" wrapText="true" textAlignment="CENTER" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity" toggleGroup="$preferencesMenu">
|
||||
<ToggleButton VBox.vgrow="ALWAYS" text="General" wrapText="true" textAlignment="CENTER" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity" toggleGroup="$preferencesMenu">
|
||||
<toggleGroup>
|
||||
<ToggleGroup fx:id="preferencesMenu" />
|
||||
</toggleGroup>
|
||||
<graphic>
|
||||
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="TOOLS" />
|
||||
</graphic>
|
||||
<userData>
|
||||
<PreferenceGroup fx:constant="GENERAL"/>
|
||||
</userData>
|
||||
</ToggleButton>
|
||||
<ToggleButton VBox.vgrow="ALWAYS" text="Server" wrapText="true" textAlignment="CENTER" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity" toggleGroup="$preferencesMenu">
|
||||
<graphic>
|
||||
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="SERVER" />
|
||||
</graphic>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<?import tornadofx.control.Fieldset?>
|
||||
<?import tornadofx.control.Field?>
|
||||
<?import com.sparrowwallet.sparrow.control.CoinLabel?>
|
||||
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
|
||||
<?import com.sparrowwallet.sparrow.control.FiatLabel?>
|
||||
|
||||
<BorderPane stylesheets="@transactions.css, @wallet.css, @../general.css" styleClass="wallet-pane" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sparrowwallet.sparrow.wallet.TransactionsController">
|
||||
<center>
|
||||
|
@ -35,7 +35,7 @@
|
|||
<CoinLabel fx:id="balance"/>
|
||||
</Field>
|
||||
<Field text="Fiat balance:">
|
||||
<CopyableLabel fx:id="fiatBalance" />
|
||||
<FiatLabel fx:id="fiatBalance" />
|
||||
</Field>
|
||||
<Field text="Mempool:">
|
||||
<CoinLabel fx:id="mempoolBalance" />
|
||||
|
|
Loading…
Reference in a new issue