mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 18:03:12 +01:00
Add supply and transactions sections
This commit is contained in:
parent
b00f96d06e
commit
44764d1fb7
@ -421,6 +421,10 @@ public class BSFormatter {
|
||||
}
|
||||
}
|
||||
|
||||
public String formatPrice(Price price, boolean appendCurrencyCode) {
|
||||
return formatPrice(price, fiatPriceFormat, true);
|
||||
}
|
||||
|
||||
public String formatPrice(Price price) {
|
||||
return formatPrice(price, fiatPriceFormat, false);
|
||||
}
|
||||
|
@ -124,6 +124,10 @@ public class BsqFormatter extends BSFormatter {
|
||||
return super.formatCoin(satoshi, coinFormat);
|
||||
}
|
||||
|
||||
public String formatBSQSatoshisWithCode(long satoshi) {
|
||||
return super.formatCoinWithCode(satoshi, coinFormat);
|
||||
}
|
||||
|
||||
public String formatBTCSatoshis(long satoshi) {
|
||||
return super.formatCoin(satoshi, btcCoinFormat);
|
||||
}
|
||||
|
@ -198,6 +198,7 @@ shared.actions=Actions
|
||||
shared.buyerUpperCase=Buyer
|
||||
shared.sellerUpperCase=Seller
|
||||
shared.new=NEW
|
||||
shared.new=NEW
|
||||
|
||||
####################################################################
|
||||
# UI views
|
||||
@ -1756,29 +1757,6 @@ dao.wallet.menuItem.receive=Receive
|
||||
dao.wallet.menuItem.transactions=Transactions
|
||||
|
||||
dao.wallet.dashboard.myBalance=My wallet balance
|
||||
dao.wallet.dashboard.distribution=Distribution of all BSQ
|
||||
dao.wallet.dashboard.locked=Global state of locked BSQ
|
||||
dao.wallet.dashboard.market=Market data
|
||||
dao.wallet.dashboard.genesis=Genesis transaction
|
||||
dao.wallet.dashboard.txDetails=BSQ transactions statistics
|
||||
dao.wallet.dashboard.genesisBlockHeight=Genesis block height
|
||||
dao.wallet.dashboard.genesisTxId=Genesis transaction ID
|
||||
dao.wallet.dashboard.genesisIssueAmount=BSQ issued at genesis transaction
|
||||
dao.wallet.dashboard.compRequestIssueAmount=BSQ issued for compensation requests
|
||||
dao.wallet.dashboard.reimbursementAmount=BSQ issued for reimbursement requests
|
||||
dao.wallet.dashboard.availableAmount=Total available BSQ
|
||||
dao.wallet.dashboard.burntAmount=Burned BSQ (fees)
|
||||
dao.wallet.dashboard.totalLockedUpAmount=Locked up in bonds
|
||||
dao.wallet.dashboard.totalUnlockingAmount=Unlocking BSQ from bonds
|
||||
dao.wallet.dashboard.totalUnlockedAmount=Unlocked BSQ from bonds
|
||||
dao.wallet.dashboard.totalConfiscatedAmount=Confiscated BSQ from bonds
|
||||
dao.wallet.dashboard.allTx=No. of all BSQ transactions
|
||||
dao.wallet.dashboard.utxo=No. of all unspent transaction outputs
|
||||
dao.wallet.dashboard.compensationIssuanceTx=No. of all compensation request issuance transactions
|
||||
dao.wallet.dashboard.reimbursementIssuanceTx=No. of all reimbursement request issuance transactions
|
||||
dao.wallet.dashboard.burntTx=No. of all fee payments transactions
|
||||
dao.wallet.dashboard.price=Latest BSQ/BTC trade price (in Bisq)
|
||||
dao.wallet.dashboard.marketCap=Market capitalisation (based on trade price)
|
||||
|
||||
dao.wallet.receive.fundYourWallet=Your BSQ receive address
|
||||
dao.wallet.receive.bsqAddress=BSQ wallet address (Fresh unused address)
|
||||
@ -1940,6 +1918,37 @@ dao.monitor.blindVote.table.hash=Hash of blind vote state
|
||||
dao.monitor.blindVote.table.prev=Previous hash
|
||||
dao.monitor.blindVote.table.numBlindVotes=No. blind votes
|
||||
|
||||
dao.factsAndFigures.menuItem.supply=Supply
|
||||
dao.factsAndFigures.menuItem.transactions=Transactions
|
||||
|
||||
dao.factsAndFigures.dashboard.marketPrice=Market data
|
||||
dao.factsAndFigures.dashboard.price=Latest BSQ/BTC trade price (in Bisq)
|
||||
dao.factsAndFigures.dashboard.marketCap=Market capitalisation (based on trade price)
|
||||
dao.factsAndFigures.dashboard.availableAmount=Total available BSQ
|
||||
|
||||
dao.factsAndFigures.supply.issued=BSQ issued
|
||||
dao.factsAndFigures.supply.genesisIssueAmount=BSQ issued at genesis transaction
|
||||
dao.factsAndFigures.supply.compRequestIssueAmount=BSQ issued for compensation requests
|
||||
dao.factsAndFigures.supply.reimbursementAmount=BSQ issued for reimbursement requests
|
||||
|
||||
dao.factsAndFigures.supply.burnt=BSQ burnt
|
||||
|
||||
dao.factsAndFigures.supply.locked=Global state of locked BSQ
|
||||
dao.factsAndFigures.supply.totalLockedUpAmount=Locked up in bonds
|
||||
dao.factsAndFigures.supply.totalUnlockingAmount=Unlocking BSQ from bonds
|
||||
dao.factsAndFigures.supply.totalUnlockedAmount=Unlocked BSQ from bonds
|
||||
dao.factsAndFigures.supply.totalConfiscatedAmount=Confiscated BSQ from bonds
|
||||
dao.factsAndFigures.supply.burntAmount=Burned BSQ (fees)
|
||||
|
||||
dao.factsAndFigures.transactions.genesis=Genesis transaction
|
||||
dao.factsAndFigures.transactions.genesisBlockHeight=Genesis block height
|
||||
dao.factsAndFigures.transactions.genesisTxId=Genesis transaction ID
|
||||
dao.factsAndFigures.transactions.txDetails=BSQ transactions statistics
|
||||
dao.factsAndFigures.transactions.allTx=No. of all BSQ transactions
|
||||
dao.factsAndFigures.transactions.utxo=No. of all unspent transaction outputs
|
||||
dao.factsAndFigures.transactions.compensationIssuanceTx=No. of all compensation request issuance transactions
|
||||
dao.factsAndFigures.transactions.reimbursementIssuanceTx=No. of all reimbursement request issuance transactions
|
||||
dao.factsAndFigures.transactions.burntTx=No. of all fee payments transactions
|
||||
|
||||
####################################################################
|
||||
# Windows
|
||||
|
@ -9,7 +9,7 @@
|
||||
* Bisq 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.
|
||||
* License for more supply.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
@ -28,7 +28,8 @@ import bisq.desktop.components.MenuItem;
|
||||
import bisq.desktop.main.MainView;
|
||||
import bisq.desktop.main.dao.DaoView;
|
||||
import bisq.desktop.main.dao.economy.dashboard.BsqDashboardView;
|
||||
import bisq.desktop.main.dao.economy.details.DetailsView;
|
||||
import bisq.desktop.main.dao.economy.supply.SupplyView;
|
||||
import bisq.desktop.main.dao.economy.transactions.BSQTransactionsView;
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
|
||||
@ -51,7 +52,7 @@ public class EconomyView extends ActivatableViewAndModel {
|
||||
private final ViewLoader viewLoader;
|
||||
private final Navigation navigation;
|
||||
|
||||
private MenuItem dashboard, details;
|
||||
private MenuItem dashboard, supply, transactions;
|
||||
private Navigation.Listener listener;
|
||||
|
||||
@FXML
|
||||
@ -81,20 +82,24 @@ public class EconomyView extends ActivatableViewAndModel {
|
||||
toggleGroup = new ToggleGroup();
|
||||
List<Class<? extends View>> baseNavPath = Arrays.asList(MainView.class, DaoView.class, EconomyView.class);
|
||||
dashboard = new MenuItem(navigation, toggleGroup, Res.get("shared.dashboard"), BsqDashboardView.class, baseNavPath);
|
||||
details = new MenuItem(navigation, toggleGroup, Res.get("shared.details"), DetailsView.class, baseNavPath);
|
||||
leftVBox.getChildren().addAll(dashboard, details);
|
||||
supply = new MenuItem(navigation, toggleGroup, Res.get("dao.factsAndFigures.menuItem.supply"), SupplyView.class, baseNavPath);
|
||||
transactions = new MenuItem(navigation, toggleGroup, Res.get("dao.factsAndFigures.menuItem.transactions"), BSQTransactionsView.class, baseNavPath);
|
||||
|
||||
leftVBox.getChildren().addAll(dashboard, supply, transactions);
|
||||
|
||||
// TODO just until DAO is enabled
|
||||
if (!DevEnv.isDaoActivated()) {
|
||||
dashboard.setDisable(true);
|
||||
details.setDisable(true);
|
||||
supply.setDisable(true);
|
||||
transactions.setDisable(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
dashboard.activate();
|
||||
details.activate();
|
||||
supply.activate();
|
||||
transactions.activate();
|
||||
|
||||
navigation.addListener(listener);
|
||||
ViewPath viewPath = navigation.getCurrentPath();
|
||||
@ -116,6 +121,8 @@ public class EconomyView extends ActivatableViewAndModel {
|
||||
navigation.removeListener(listener);
|
||||
|
||||
dashboard.deactivate();
|
||||
supply.deactivate();
|
||||
transactions.deactivate();
|
||||
}
|
||||
|
||||
private void loadView(Class<? extends View> viewClass) {
|
||||
@ -123,6 +130,7 @@ public class EconomyView extends ActivatableViewAndModel {
|
||||
content.getChildren().setAll(view.getRoot());
|
||||
|
||||
if (view instanceof BsqDashboardView) toggleGroup.selectToggle(dashboard);
|
||||
else if (view instanceof DetailsView) toggleGroup.selectToggle(details);
|
||||
else if (view instanceof SupplyView) toggleGroup.selectToggle(supply);
|
||||
else if (view instanceof BSQTransactionsView) toggleGroup.selectToggle(transactions);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,6 @@
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints percentWidth="50"/>
|
||||
<ColumnConstraints minWidth="10" maxWidth="5"/>
|
||||
<ColumnConstraints percentWidth="50"/>
|
||||
</columnConstraints>
|
||||
</GridPane>
|
||||
|
@ -19,30 +19,94 @@ package bisq.desktop.main.dao.economy.dashboard;
|
||||
|
||||
import bisq.desktop.common.view.ActivatableView;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.TitledGroupBg;
|
||||
import bisq.desktop.util.FormBuilder;
|
||||
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.state.DaoStateListener;
|
||||
import bisq.core.dao.state.DaoStateService;
|
||||
import bisq.core.dao.state.model.blockchain.Block;
|
||||
import bisq.core.dao.state.model.governance.IssuanceType;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.statistics.TradeStatistics2;
|
||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.util.BSFormatter;
|
||||
import bisq.core.util.BsqFormatter;
|
||||
|
||||
import bisq.common.util.Tuple3;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import javafx.scene.chart.AreaChart;
|
||||
import javafx.scene.chart.NumberAxis;
|
||||
import javafx.scene.chart.XYChart;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Side;
|
||||
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
||||
import static bisq.desktop.util.FormBuilder.addTopLabelReadOnlyTextField;
|
||||
import static bisq.desktop.util.Layout.FIRST_ROW_DISTANCE;
|
||||
|
||||
|
||||
|
||||
import java.sql.Date;
|
||||
|
||||
@FxmlView
|
||||
public class BsqDashboardView extends ActivatableView<GridPane, Void> implements DaoStateListener {
|
||||
|
||||
private static final String DAY = "day";
|
||||
private static final Map<String, TemporalAdjuster> ADJUSTERS = new HashMap<>();
|
||||
|
||||
private final DaoFacade daoFacade;
|
||||
private final TradeStatisticsManager tradeStatisticsManager;
|
||||
private final PriceFeedService priceFeedService;
|
||||
private final DaoStateService daoStateService;
|
||||
private final Preferences preferences;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
private final BSFormatter btcFormatter;
|
||||
|
||||
private ChangeListener<Number> priceChangeListener;
|
||||
|
||||
private AreaChart bsqPriceChart;
|
||||
private XYChart.Series<Number, Number> seriesBSQAdded, seriesBSQBurnt;
|
||||
private XYChart.Series<Number, Number> seriesBSQPrice;
|
||||
|
||||
private TextField marketCapTextField, priceTextField, availableAmountTextField;
|
||||
|
||||
private Coin availableAmount;
|
||||
|
||||
private int gridRow = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
@ -50,20 +114,52 @@ public class BsqDashboardView extends ActivatableView<GridPane, Void> implements
|
||||
|
||||
@Inject
|
||||
private BsqDashboardView(DaoFacade daoFacade,
|
||||
TradeStatisticsManager tradeStatisticsManager,
|
||||
PriceFeedService priceFeedService,
|
||||
DaoStateService daoStateService,
|
||||
Preferences preferences,
|
||||
BsqFormatter bsqFormatter) {
|
||||
BsqFormatter bsqFormatter,
|
||||
BSFormatter btcFormatter) {
|
||||
this.daoFacade = daoFacade;
|
||||
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||
this.priceFeedService = priceFeedService;
|
||||
this.daoStateService = daoStateService;
|
||||
this.preferences = preferences;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
this.btcFormatter = btcFormatter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
|
||||
ADJUSTERS.put(DAY, TemporalAdjusters.ofDateAdjuster(d -> d));
|
||||
|
||||
createKPIs();
|
||||
createChart();
|
||||
|
||||
priceChangeListener = (observable, oldValue, newValue) -> updatePrice();
|
||||
}
|
||||
|
||||
private void createKPIs() {
|
||||
|
||||
TitledGroupBg titledGroupBg = addTitledGroupBg(root, gridRow, 5, Res.get("dao.factsAndFigures.dashboard.marketPrice"));
|
||||
titledGroupBg.getStyleClass().add("last");
|
||||
|
||||
Tuple3<Label, TextField, VBox> marketPriceTuple = addTopLabelReadOnlyTextField(root, gridRow, Res.get("dao.factsAndFigures.dashboard.price"),
|
||||
FIRST_ROW_DISTANCE);
|
||||
priceTextField = marketPriceTuple.second;
|
||||
|
||||
GridPane.setColumnSpan(marketPriceTuple.third, 2);
|
||||
|
||||
marketCapTextField = addTopLabelReadOnlyTextField(root, ++gridRow,
|
||||
Res.get("dao.factsAndFigures.dashboard.marketCap")).second;
|
||||
|
||||
availableAmountTextField = FormBuilder.addTopLabelReadOnlyTextField(root, gridRow, 1,
|
||||
Res.get("dao.factsAndFigures.dashboard.availableAmount")).second;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
daoFacade.addBsqStateListener(this);
|
||||
@ -71,15 +167,16 @@ public class BsqDashboardView extends ActivatableView<GridPane, Void> implements
|
||||
|
||||
updateWithBsqBlockChainData();
|
||||
updatePrice();
|
||||
updateChartData();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
daoFacade.removeBsqStateListener(this);
|
||||
priceFeedService.updateCounterProperty().removeListener(priceChangeListener);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DaoStateListener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -94,10 +191,123 @@ public class BsqDashboardView extends ActivatableView<GridPane, Void> implements
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void createChart() {
|
||||
NumberAxis xAxis = new NumberAxis();
|
||||
xAxis.setForceZeroInRange(false);
|
||||
xAxis.setAutoRanging(true);
|
||||
xAxis.setTickLabelGap(6);
|
||||
xAxis.setTickMarkVisible(false);
|
||||
xAxis.setMinorTickVisible(false);
|
||||
|
||||
xAxis.setTickLabelFormatter(new StringConverter<>() {
|
||||
@Override
|
||||
public String toString(Number timestamp) {
|
||||
LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(timestamp.longValue(),
|
||||
0, OffsetDateTime.now(ZoneId.systemDefault()).getOffset());
|
||||
return localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number fromString(String string) {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
NumberAxis yAxis = new NumberAxis();
|
||||
yAxis.setForceZeroInRange(false);
|
||||
yAxis.setSide(Side.RIGHT);
|
||||
yAxis.setAutoRanging(true);
|
||||
yAxis.setTickMarkVisible(false);
|
||||
yAxis.setMinorTickVisible(false);
|
||||
yAxis.setTickLabelGap(5);
|
||||
yAxis.setTickLabelFormatter(new StringConverter<>() {
|
||||
@Override
|
||||
public String toString(Number marketPrice) {
|
||||
return bsqFormatter.formatBTCWithCode(marketPrice.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number fromString(String string) {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
seriesBSQPrice = new XYChart.Series<>();
|
||||
seriesBSQPrice.setName("Price in BTC for 1 BSQ");
|
||||
|
||||
bsqPriceChart = new AreaChart<>(xAxis, yAxis);
|
||||
bsqPriceChart.setLegendVisible(true);
|
||||
bsqPriceChart.setAnimated(false);
|
||||
bsqPriceChart.setId("charts");
|
||||
bsqPriceChart.setMinHeight(250);
|
||||
bsqPriceChart.setPrefHeight(250);
|
||||
bsqPriceChart.setCreateSymbols(true);
|
||||
bsqPriceChart.setPadding(new Insets(0));
|
||||
bsqPriceChart.getData().addAll(seriesBSQPrice);
|
||||
|
||||
GridPane.setRowIndex(bsqPriceChart, ++gridRow);
|
||||
GridPane.setColumnSpan(bsqPriceChart, 2);
|
||||
|
||||
root.getChildren().addAll(bsqPriceChart);
|
||||
}
|
||||
|
||||
private void updateChartData() {
|
||||
updateBSQPriceData();
|
||||
}
|
||||
|
||||
private void updateBSQPriceData() {
|
||||
seriesBSQPrice.getData().clear();
|
||||
|
||||
Map<LocalDate, List<TradeStatistics2>> bsqPriceByDate = tradeStatisticsManager.getObservableTradeStatisticsSet().stream()
|
||||
.filter(e -> e.getCurrencyCode().equals("BSQ"))
|
||||
.sorted(Comparator.comparing(TradeStatistics2::getTradeDate))
|
||||
.collect(Collectors.groupingBy(item -> new Date(item.getTradeDate().getTime()).toLocalDate()
|
||||
.with(ADJUSTERS.get(DAY))));
|
||||
|
||||
List<XYChart.Data<Number, Number>> updatedBSQPrice = bsqPriceByDate.keySet().stream()
|
||||
.map(e -> {
|
||||
ZonedDateTime zonedDateTime = e.atStartOfDay(ZoneId.systemDefault());
|
||||
return new XYChart.Data<Number, Number>(zonedDateTime.toInstant().getEpochSecond(), bsqPriceByDate.get(e).stream()
|
||||
.map(TradeStatistics2::getTradePrice)
|
||||
.mapToDouble(Price::getValue)
|
||||
.average()
|
||||
.orElse(Double.NaN)
|
||||
);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
seriesBSQPrice.getData().setAll(updatedBSQPrice);
|
||||
}
|
||||
|
||||
private void updateWithBsqBlockChainData() {
|
||||
Coin issuedAmountFromGenesis = daoFacade.getGenesisTotalSupply();
|
||||
Coin issuedAmountFromCompRequests = Coin.valueOf(daoFacade.getTotalIssuedAmount(IssuanceType.COMPENSATION));
|
||||
Coin issuedAmountFromReimbursementRequests = Coin.valueOf(daoFacade.getTotalIssuedAmount(IssuanceType.REIMBURSEMENT));
|
||||
Coin burntFee = Coin.valueOf(daoFacade.getTotalBurntFee());
|
||||
Coin totalConfiscatedAmount = Coin.valueOf(daoFacade.getTotalAmountOfConfiscatedTxOutputs());
|
||||
|
||||
availableAmount = issuedAmountFromGenesis
|
||||
.add(issuedAmountFromCompRequests)
|
||||
.add(issuedAmountFromReimbursementRequests)
|
||||
.subtract(burntFee)
|
||||
.subtract(totalConfiscatedAmount);
|
||||
|
||||
availableAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(availableAmount));
|
||||
}
|
||||
|
||||
private void updatePrice() {
|
||||
Optional<Price> optionalBsqPrice = priceFeedService.getBsqPrice();
|
||||
if (optionalBsqPrice.isPresent()) {
|
||||
Price bsqPrice = optionalBsqPrice.get();
|
||||
priceTextField.setText(bsqFormatter.formatPrice(bsqPrice) + " BSQ/BTC");
|
||||
|
||||
marketCapTextField.setText(bsqFormatter.formatMarketCap(priceFeedService.getMarketPrice("BSQ"),
|
||||
priceFeedService.getMarketPrice(preferences.getPreferredTradeCurrency().getCode()),
|
||||
availableAmount));
|
||||
} else {
|
||||
priceTextField.setText(Res.get("shared.na"));
|
||||
marketCapTextField.setText(Res.get("shared.na"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,225 +0,0 @@
|
||||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq 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.
|
||||
*
|
||||
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.desktop.main.dao.economy.details;
|
||||
|
||||
import bisq.desktop.common.view.ActivatableView;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.util.FormBuilder;
|
||||
import bisq.desktop.util.Layout;
|
||||
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.state.DaoStateListener;
|
||||
import bisq.core.dao.state.model.blockchain.Block;
|
||||
import bisq.core.dao.state.model.governance.IssuanceType;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.util.BsqFormatter;
|
||||
|
||||
import bisq.common.util.Tuple3;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
||||
import static bisq.desktop.util.FormBuilder.addTopLabelReadOnlyTextField;
|
||||
|
||||
@FxmlView
|
||||
public class DetailsView extends ActivatableView<GridPane, Void> implements DaoStateListener {
|
||||
|
||||
private final DaoFacade daoFacade;
|
||||
private final PriceFeedService priceFeedService;
|
||||
private final Preferences preferences;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
|
||||
private int gridRow = 0;
|
||||
private TextField genesisIssueAmountTextField, compRequestIssueAmountTextField, reimbursementAmountTextField, availableAmountTextField,
|
||||
burntAmountTextField, totalLockedUpAmountTextField, totalUnlockingAmountTextField,
|
||||
totalUnlockedAmountTextField, totalConfiscatedAmountTextField, allTxTextField, burntTxTextField,
|
||||
utxoTextField, compensationIssuanceTxTextField,
|
||||
reimbursementIssuanceTxTextField, priceTextField, marketCapTextField;
|
||||
private ChangeListener<Number> priceChangeListener;
|
||||
private Coin availableAmount;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private DetailsView(DaoFacade daoFacade,
|
||||
PriceFeedService priceFeedService,
|
||||
Preferences preferences,
|
||||
BsqFormatter bsqFormatter) {
|
||||
this.daoFacade = daoFacade;
|
||||
this.priceFeedService = priceFeedService;
|
||||
this.preferences = preferences;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
int columnIndex = 2;
|
||||
|
||||
int startRow = gridRow;
|
||||
addTitledGroupBg(root, ++gridRow, 5, Res.get("dao.wallet.dashboard.distribution"));
|
||||
genesisIssueAmountTextField = FormBuilder.addTopLabelReadOnlyTextField(root, gridRow, Res.get("dao.wallet.dashboard.genesisIssueAmount")).second;
|
||||
compRequestIssueAmountTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.compRequestIssueAmount")).second;
|
||||
reimbursementAmountTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.reimbursementAmount")).second;
|
||||
burntAmountTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.burntAmount")).second;
|
||||
availableAmountTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.availableAmount")).second;
|
||||
|
||||
gridRow = startRow;
|
||||
addTitledGroupBg(root, ++gridRow, columnIndex, 5, Res.get("dao.wallet.dashboard.locked"), Layout.GROUP_DISTANCE);
|
||||
totalLockedUpAmountTextField = FormBuilder.addTopLabelReadOnlyTextField(root, gridRow, columnIndex, Res.get("dao.wallet.dashboard.totalLockedUpAmount"), Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
||||
totalUnlockingAmountTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, columnIndex, Res.get("dao.wallet.dashboard.totalUnlockingAmount")).second;
|
||||
totalUnlockedAmountTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, columnIndex, Res.get("dao.wallet.dashboard.totalUnlockedAmount")).second;
|
||||
totalConfiscatedAmountTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, columnIndex, Res.get("dao.wallet.dashboard.totalConfiscatedAmount")).second;
|
||||
gridRow++;
|
||||
|
||||
startRow = gridRow;
|
||||
addTitledGroupBg(root, ++gridRow, 2, Res.get("dao.wallet.dashboard.market"), Layout.GROUP_DISTANCE);
|
||||
priceTextField = FormBuilder.addTopLabelReadOnlyTextField(root, gridRow, Res.get("dao.wallet.dashboard.price"), Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
||||
marketCapTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.marketCap")).second;
|
||||
|
||||
gridRow = startRow;
|
||||
addTitledGroupBg(root, ++gridRow, columnIndex, 2, Res.get("dao.wallet.dashboard.genesis"), Layout.GROUP_DISTANCE);
|
||||
String genTxHeight = String.valueOf(daoFacade.getGenesisBlockHeight());
|
||||
String genesisTxId = daoFacade.getGenesisTxId();
|
||||
String url = preferences.getBsqBlockChainExplorer().txUrl + genesisTxId;
|
||||
addTopLabelReadOnlyTextField(root, gridRow, columnIndex, Res.get("dao.wallet.dashboard.genesisBlockHeight"),
|
||||
genTxHeight, Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
|
||||
// TODO use addTopLabelTxIdTextField
|
||||
Tuple3<Label, HyperlinkWithIcon, VBox> tuple = FormBuilder.addTopLabelHyperlinkWithIcon(root, ++gridRow, columnIndex,
|
||||
Res.get("dao.wallet.dashboard.genesisTxId"), genesisTxId, url, 0);
|
||||
HyperlinkWithIcon hyperlinkWithIcon = tuple.second;
|
||||
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", genesisTxId)));
|
||||
|
||||
startRow = gridRow;
|
||||
addTitledGroupBg(root, ++gridRow, 3, Res.get("dao.wallet.dashboard.txDetails"), Layout.GROUP_DISTANCE);
|
||||
allTxTextField = FormBuilder.addTopLabelReadOnlyTextField(root, gridRow, Res.get("dao.wallet.dashboard.allTx"),
|
||||
genTxHeight, Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
||||
utxoTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.utxo")).second;
|
||||
compensationIssuanceTxTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow,
|
||||
Res.get("dao.wallet.dashboard.compensationIssuanceTx")).second;
|
||||
|
||||
gridRow = startRow;
|
||||
addTitledGroupBg(root, ++gridRow, columnIndex, 3, "", Layout.GROUP_DISTANCE);
|
||||
reimbursementIssuanceTxTextField = FormBuilder.addTopLabelReadOnlyTextField(root, gridRow, columnIndex,
|
||||
Res.get("dao.wallet.dashboard.reimbursementIssuanceTx"),
|
||||
Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
||||
burntTxTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, columnIndex,
|
||||
Res.get("dao.wallet.dashboard.burntTx")).second;
|
||||
++gridRow;
|
||||
|
||||
priceChangeListener = (observable, oldValue, newValue) -> updatePrice();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
daoFacade.addBsqStateListener(this);
|
||||
priceFeedService.updateCounterProperty().addListener(priceChangeListener);
|
||||
|
||||
updateWithBsqBlockChainData();
|
||||
updatePrice();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
daoFacade.removeBsqStateListener(this);
|
||||
priceFeedService.updateCounterProperty().removeListener(priceChangeListener);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DaoStateListener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onParseBlockCompleteAfterBatchProcessing(Block block) {
|
||||
updateWithBsqBlockChainData();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void updateWithBsqBlockChainData() {
|
||||
Coin issuedAmountFromGenesis = daoFacade.getGenesisTotalSupply();
|
||||
genesisIssueAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(issuedAmountFromGenesis));
|
||||
|
||||
Coin issuedAmountFromCompRequests = Coin.valueOf(daoFacade.getTotalIssuedAmount(IssuanceType.COMPENSATION));
|
||||
compRequestIssueAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(issuedAmountFromCompRequests));
|
||||
Coin issuedAmountFromReimbursementRequests = Coin.valueOf(daoFacade.getTotalIssuedAmount(IssuanceType.REIMBURSEMENT));
|
||||
reimbursementAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(issuedAmountFromReimbursementRequests));
|
||||
|
||||
Coin burntFee = Coin.valueOf(daoFacade.getTotalBurntFee());
|
||||
Coin totalLockedUpAmount = Coin.valueOf(daoFacade.getTotalLockupAmount());
|
||||
Coin totalUnlockingAmount = Coin.valueOf(daoFacade.getTotalAmountOfUnLockingTxOutputs());
|
||||
Coin totalUnlockedAmount = Coin.valueOf(daoFacade.getTotalAmountOfUnLockedTxOutputs());
|
||||
Coin totalConfiscatedAmount = Coin.valueOf(daoFacade.getTotalAmountOfConfiscatedTxOutputs());
|
||||
availableAmount = issuedAmountFromGenesis
|
||||
.add(issuedAmountFromCompRequests)
|
||||
.add(issuedAmountFromReimbursementRequests)
|
||||
.subtract(burntFee)
|
||||
.subtract(totalConfiscatedAmount);
|
||||
|
||||
availableAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(availableAmount));
|
||||
burntAmountTextField.setText("-" + bsqFormatter.formatAmountWithGroupSeparatorAndCode(burntFee));
|
||||
totalLockedUpAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(totalLockedUpAmount));
|
||||
totalUnlockingAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(totalUnlockingAmount));
|
||||
totalUnlockedAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(totalUnlockedAmount));
|
||||
totalConfiscatedAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(totalConfiscatedAmount));
|
||||
allTxTextField.setText(String.valueOf(daoFacade.getTxs().size()));
|
||||
utxoTextField.setText(String.valueOf(daoFacade.getUnspentTxOutputs().size()));
|
||||
compensationIssuanceTxTextField.setText(String.valueOf(daoFacade.getNumIssuanceTransactions(IssuanceType.COMPENSATION)));
|
||||
reimbursementIssuanceTxTextField.setText(String.valueOf(daoFacade.getNumIssuanceTransactions(IssuanceType.REIMBURSEMENT)));
|
||||
burntTxTextField.setText(String.valueOf(daoFacade.getFeeTxs().size()));
|
||||
}
|
||||
|
||||
private void updatePrice() {
|
||||
Optional<Price> optionalBsqPrice = priceFeedService.getBsqPrice();
|
||||
if (optionalBsqPrice.isPresent()) {
|
||||
Price bsqPrice = optionalBsqPrice.get();
|
||||
priceTextField.setText(bsqFormatter.formatPrice(bsqPrice) + " BSQ/BTC");
|
||||
|
||||
marketCapTextField.setText(bsqFormatter.formatMarketCap(priceFeedService.getMarketPrice("BSQ"),
|
||||
priceFeedService.getMarketPrice(preferences.getPreferredTradeCurrency().getCode()),
|
||||
availableAmount));
|
||||
} else {
|
||||
priceTextField.setText(Res.get("shared.na"));
|
||||
marketCapTextField.setText(Res.get("shared.na"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,14 +20,13 @@
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<GridPane fx:id="root" fx:controller="bisq.desktop.main.dao.economy.details.DetailsView"
|
||||
<GridPane fx:id="root" fx:controller="bisq.desktop.main.dao.economy.supply.SupplyView"
|
||||
hgap="5.0" vgap="5.0"
|
||||
AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0"
|
||||
AnchorPane.rightAnchor="25.0" AnchorPane.topAnchor="20.0"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints percentWidth="50"/>
|
||||
<ColumnConstraints minWidth="10" maxWidth="5"/>
|
||||
<ColumnConstraints percentWidth="50"/>
|
||||
</columnConstraints>
|
||||
</GridPane>
|
@ -0,0 +1,322 @@
|
||||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq 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.
|
||||
*
|
||||
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.desktop.main.dao.economy.supply;
|
||||
|
||||
import bisq.desktop.common.view.ActivatableView;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.TitledGroupBg;
|
||||
import bisq.desktop.util.Layout;
|
||||
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.state.DaoStateListener;
|
||||
import bisq.core.dao.state.DaoStateService;
|
||||
import bisq.core.dao.state.model.blockchain.Block;
|
||||
import bisq.core.dao.state.model.blockchain.Tx;
|
||||
import bisq.core.dao.state.model.governance.Issuance;
|
||||
import bisq.core.dao.state.model.governance.IssuanceType;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.util.BsqFormatter;
|
||||
|
||||
import bisq.common.util.Tuple3;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import javafx.scene.chart.AreaChart;
|
||||
import javafx.scene.chart.NumberAxis;
|
||||
import javafx.scene.chart.XYChart;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Side;
|
||||
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
||||
import static bisq.desktop.util.FormBuilder.addTopLabelReadOnlyTextField;
|
||||
|
||||
|
||||
|
||||
import java.sql.Date;
|
||||
|
||||
@FxmlView
|
||||
public class SupplyView extends ActivatableView<GridPane, Void> implements DaoStateListener {
|
||||
|
||||
private static final String MONTH = "month";
|
||||
|
||||
private final DaoFacade daoFacade;
|
||||
private DaoStateService daoStateService;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
|
||||
private int gridRow = 0;
|
||||
private TextField genesisIssueAmountTextField, compRequestIssueAmountTextField, reimbursementAmountTextField,
|
||||
burntAmountTextField, totalLockedUpAmountTextField, totalUnlockingAmountTextField,
|
||||
totalUnlockedAmountTextField, totalConfiscatedAmountTextField;
|
||||
private XYChart.Series<Number, Number> seriesBSQIssued, seriesBSQBurnt;
|
||||
|
||||
private static final Map<String, TemporalAdjuster> ADJUSTERS = new HashMap<>();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private SupplyView(DaoFacade daoFacade,
|
||||
DaoStateService daoStateService,
|
||||
BsqFormatter bsqFormatter) {
|
||||
this.daoFacade = daoFacade;
|
||||
this.daoStateService = daoStateService;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
|
||||
ADJUSTERS.put(MONTH, TemporalAdjusters.firstDayOfMonth());
|
||||
|
||||
createSupplyIncreasedInformation();
|
||||
createSupplyReducedInformation();
|
||||
createSupplyLockedInformation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
daoFacade.addBsqStateListener(this);
|
||||
|
||||
updateWithBsqBlockChainData();
|
||||
updateBSQTokenData();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
daoFacade.removeBsqStateListener(this);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DaoStateListener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onParseBlockCompleteAfterBatchProcessing(Block block) {
|
||||
updateWithBsqBlockChainData();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void createSupplyIncreasedInformation() {
|
||||
addTitledGroupBg(root, ++gridRow, 3, Res.get("dao.factsAndFigures.supply.issued"));
|
||||
|
||||
Tuple3<Label, TextField, VBox> genesisAmountTuple = addTopLabelReadOnlyTextField(root, gridRow,
|
||||
Res.get("dao.factsAndFigures.supply.genesisIssueAmount"), Layout.FIRST_ROW_DISTANCE);
|
||||
genesisIssueAmountTextField = genesisAmountTuple.second;
|
||||
GridPane.setColumnSpan(genesisAmountTuple.third, 2);
|
||||
|
||||
compRequestIssueAmountTextField = addTopLabelReadOnlyTextField(root, ++gridRow,
|
||||
Res.get("dao.factsAndFigures.supply.compRequestIssueAmount")).second;
|
||||
reimbursementAmountTextField = addTopLabelReadOnlyTextField(root, gridRow, 1,
|
||||
Res.get("dao.factsAndFigures.supply.reimbursementAmount")).second;
|
||||
|
||||
|
||||
seriesBSQIssued = new XYChart.Series<>();
|
||||
createChart(seriesBSQIssued, Res.get("dao.factsAndFigures.supply.issued"));
|
||||
}
|
||||
|
||||
private void createSupplyReducedInformation() {
|
||||
addTitledGroupBg(root, ++gridRow, 2, Res.get("dao.factsAndFigures.supply.burnt"), Layout.GROUP_DISTANCE);
|
||||
|
||||
Tuple3<Label, TextField, VBox> burntAmountTuple = addTopLabelReadOnlyTextField(root, gridRow,
|
||||
Res.get("dao.factsAndFigures.supply.burntAmount"), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
burntAmountTextField = burntAmountTuple.second;
|
||||
|
||||
GridPane.setColumnSpan(burntAmountTuple.third, 2);
|
||||
|
||||
seriesBSQBurnt = new XYChart.Series<>();
|
||||
createChart(seriesBSQBurnt, Res.get("dao.factsAndFigures.supply.burnt"));
|
||||
}
|
||||
|
||||
private void createSupplyLockedInformation() {
|
||||
TitledGroupBg titledGroupBg = addTitledGroupBg(root, ++gridRow, 2, Res.get("dao.factsAndFigures.supply.locked"), Layout.GROUP_DISTANCE);
|
||||
titledGroupBg.getStyleClass().add("last");
|
||||
|
||||
totalLockedUpAmountTextField = addTopLabelReadOnlyTextField(root, gridRow,
|
||||
Res.get("dao.factsAndFigures.supply.totalLockedUpAmount"),
|
||||
Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
||||
totalUnlockingAmountTextField = addTopLabelReadOnlyTextField(root, gridRow, 1,
|
||||
Res.get("dao.factsAndFigures.supply.totalUnlockingAmount"),
|
||||
Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
||||
|
||||
totalUnlockedAmountTextField = addTopLabelReadOnlyTextField(root, ++gridRow,
|
||||
Res.get("dao.factsAndFigures.supply.totalUnlockedAmount")).second;
|
||||
totalConfiscatedAmountTextField = addTopLabelReadOnlyTextField(root, gridRow, 1,
|
||||
Res.get("dao.factsAndFigures.supply.totalConfiscatedAmount")).second;
|
||||
|
||||
}
|
||||
|
||||
private void createChart(XYChart.Series<Number, Number> series, String seriesLabel) {
|
||||
NumberAxis xAxis = new NumberAxis();
|
||||
xAxis.setForceZeroInRange(false);
|
||||
xAxis.setAutoRanging(true);
|
||||
xAxis.setTickLabelGap(6);
|
||||
xAxis.setTickMarkVisible(false);
|
||||
xAxis.setMinorTickVisible(false);
|
||||
xAxis.setTickLabelFormatter(new StringConverter<>() {
|
||||
@Override
|
||||
public String toString(Number timestamp) {
|
||||
LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(timestamp.longValue(),
|
||||
0, OffsetDateTime.now(ZoneId.systemDefault()).getOffset());
|
||||
return localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number fromString(String string) {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
NumberAxis yAxis = new NumberAxis();
|
||||
yAxis.setForceZeroInRange(false);
|
||||
yAxis.setSide(Side.RIGHT);
|
||||
yAxis.setAutoRanging(true);
|
||||
yAxis.setTickMarkVisible(false);
|
||||
yAxis.setMinorTickVisible(false);
|
||||
yAxis.setTickLabelGap(5);
|
||||
yAxis.setTickLabelFormatter(new StringConverter<>() {
|
||||
@Override
|
||||
public String toString(Number marketPrice) {
|
||||
return bsqFormatter.formatBSQSatoshisWithCode(marketPrice.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number fromString(String string) {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
series.setName(seriesLabel);
|
||||
|
||||
AreaChart<Number, Number> chart = new AreaChart<>(xAxis, yAxis);
|
||||
chart.setLegendVisible(true);
|
||||
chart.setAnimated(false);
|
||||
chart.setId("charts");
|
||||
chart.setMinHeight(250);
|
||||
chart.setPrefHeight(250);
|
||||
chart.setCreateSymbols(true);
|
||||
chart.setPadding(new Insets(0));
|
||||
chart.getData().addAll(series);
|
||||
|
||||
GridPane.setColumnSpan(chart, 2);
|
||||
GridPane.setRowIndex(chart, ++gridRow);
|
||||
|
||||
root.getChildren().add(chart);
|
||||
}
|
||||
|
||||
private void updateWithBsqBlockChainData() {
|
||||
Coin issuedAmountFromGenesis = daoFacade.getGenesisTotalSupply();
|
||||
genesisIssueAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(issuedAmountFromGenesis));
|
||||
|
||||
Coin issuedAmountFromCompRequests = Coin.valueOf(daoFacade.getTotalIssuedAmount(IssuanceType.COMPENSATION));
|
||||
compRequestIssueAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(issuedAmountFromCompRequests));
|
||||
Coin issuedAmountFromReimbursementRequests = Coin.valueOf(daoFacade.getTotalIssuedAmount(IssuanceType.REIMBURSEMENT));
|
||||
reimbursementAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(issuedAmountFromReimbursementRequests));
|
||||
|
||||
Coin burntFee = Coin.valueOf(daoFacade.getTotalBurntFee());
|
||||
Coin totalLockedUpAmount = Coin.valueOf(daoFacade.getTotalLockupAmount());
|
||||
Coin totalUnlockingAmount = Coin.valueOf(daoFacade.getTotalAmountOfUnLockingTxOutputs());
|
||||
Coin totalUnlockedAmount = Coin.valueOf(daoFacade.getTotalAmountOfUnLockedTxOutputs());
|
||||
Coin totalConfiscatedAmount = Coin.valueOf(daoFacade.getTotalAmountOfConfiscatedTxOutputs());
|
||||
|
||||
burntAmountTextField.setText("-" + bsqFormatter.formatAmountWithGroupSeparatorAndCode(burntFee));
|
||||
totalLockedUpAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(totalLockedUpAmount));
|
||||
totalUnlockingAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(totalUnlockingAmount));
|
||||
totalUnlockedAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(totalUnlockedAmount));
|
||||
totalConfiscatedAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(totalConfiscatedAmount));
|
||||
}
|
||||
|
||||
private void updateBSQTokenData() {
|
||||
seriesBSQIssued.getData().clear();
|
||||
seriesBSQBurnt.getData().clear();
|
||||
|
||||
Map<LocalDate, List<Tx>> feesBurntByMonth = daoStateService.getBurntFeeTxs().stream()
|
||||
.sorted(Comparator.comparing(Tx::getTime))
|
||||
.collect(Collectors.groupingBy(item -> new Date(item.getTime()).toLocalDate()
|
||||
.with(ADJUSTERS.get(MONTH))));
|
||||
|
||||
List<XYChart.Data<Number, Number>> updatedBurntBSQ = feesBurntByMonth.keySet().stream()
|
||||
.map(date -> {
|
||||
ZonedDateTime zonedDateTime = date.atStartOfDay(ZoneId.systemDefault());
|
||||
return new XYChart.Data<Number, Number>(zonedDateTime.toInstant().getEpochSecond(), feesBurntByMonth.get(date)
|
||||
.stream()
|
||||
.mapToDouble(Tx::getBurntFee)
|
||||
.sum()
|
||||
);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
seriesBSQBurnt.getData().setAll(updatedBurntBSQ);
|
||||
|
||||
Stream<Issuance> bsqByCompensation = daoStateService.getIssuanceSet(IssuanceType.COMPENSATION).stream()
|
||||
.sorted(Comparator.comparing(Issuance::getChainHeight));
|
||||
|
||||
Stream<Issuance> bsqByReImbursement = daoStateService.getIssuanceSet(IssuanceType.REIMBURSEMENT).stream()
|
||||
.sorted(Comparator.comparing(Issuance::getChainHeight));
|
||||
|
||||
Map<LocalDate, List<Issuance>> bsqAddedByVote = Stream.concat(bsqByCompensation, bsqByReImbursement)
|
||||
.collect(Collectors.groupingBy(item -> new Date(daoFacade.getBlockTime(item.getChainHeight())).toLocalDate()
|
||||
.with(ADJUSTERS.get(MONTH))));
|
||||
|
||||
List<XYChart.Data<Number, Number>> updatedAddedBSQ = bsqAddedByVote.keySet().stream()
|
||||
.map(date -> {
|
||||
ZonedDateTime zonedDateTime = date.atStartOfDay(ZoneId.systemDefault());
|
||||
return new XYChart.Data<Number, Number>(zonedDateTime.toInstant().getEpochSecond(), bsqAddedByVote.get(date)
|
||||
.stream()
|
||||
.mapToDouble(Issuance::getAmount)
|
||||
.sum());
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
seriesBSQIssued.getData().setAll(updatedAddedBSQ);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
~ This file is part of Bisq.
|
||||
~
|
||||
~ Bisq 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.
|
||||
~
|
||||
~ Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<GridPane fx:id="root" fx:controller="bisq.desktop.main.dao.economy.transactions.BSQTransactionsView"
|
||||
hgap="5.0" vgap="5.0"
|
||||
AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0"
|
||||
AnchorPane.rightAnchor="25.0" AnchorPane.topAnchor="20.0"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints percentWidth="50"/>
|
||||
<ColumnConstraints percentWidth="50"/>
|
||||
</columnConstraints>
|
||||
</GridPane>
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq 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.
|
||||
*
|
||||
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.desktop.main.dao.economy.transactions;
|
||||
|
||||
import bisq.desktop.common.view.ActivatableView;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.TitledGroupBg;
|
||||
import bisq.desktop.util.Layout;
|
||||
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.state.DaoStateListener;
|
||||
import bisq.core.dao.state.model.blockchain.Block;
|
||||
import bisq.core.dao.state.model.governance.IssuanceType;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.user.Preferences;
|
||||
|
||||
import bisq.common.util.Tuple3;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
||||
import static bisq.desktop.util.FormBuilder.addTopLabelHyperlinkWithIcon;
|
||||
import static bisq.desktop.util.FormBuilder.addTopLabelReadOnlyTextField;
|
||||
|
||||
@FxmlView
|
||||
public class BSQTransactionsView extends ActivatableView<GridPane, Void> implements DaoStateListener {
|
||||
|
||||
private final DaoFacade daoFacade;
|
||||
private final Preferences preferences;
|
||||
|
||||
private int gridRow = 0;
|
||||
private TextField allTxTextField, burntTxTextField,
|
||||
utxoTextField, compensationIssuanceTxTextField,
|
||||
reimbursementIssuanceTxTextField;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private BSQTransactionsView(DaoFacade daoFacade,
|
||||
Preferences preferences) {
|
||||
this.daoFacade = daoFacade;
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
addTitledGroupBg(root, gridRow, 2, Res.get("dao.factsAndFigures.transactions.genesis"));
|
||||
String genTxHeight = String.valueOf(daoFacade.getGenesisBlockHeight());
|
||||
String genesisTxId = daoFacade.getGenesisTxId();
|
||||
String url = preferences.getBsqBlockChainExplorer().txUrl + genesisTxId;
|
||||
|
||||
GridPane.setColumnSpan(addTopLabelReadOnlyTextField(root, gridRow, Res.get("dao.factsAndFigures.transactions.genesisBlockHeight"),
|
||||
genTxHeight, Layout.FIRST_ROW_DISTANCE).third, 2);
|
||||
|
||||
// TODO use addTopLabelTxIdTextField
|
||||
Tuple3<Label, HyperlinkWithIcon, VBox> tuple = addTopLabelHyperlinkWithIcon(root, ++gridRow,
|
||||
Res.get("dao.factsAndFigures.transactions.genesisTxId"), genesisTxId, url, 0);
|
||||
HyperlinkWithIcon hyperlinkWithIcon = tuple.second;
|
||||
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", genesisTxId)));
|
||||
|
||||
GridPane.setColumnSpan(tuple.third, 2);
|
||||
|
||||
|
||||
int startRow = ++gridRow;
|
||||
|
||||
TitledGroupBg titledGroupBg = addTitledGroupBg(root, gridRow, 3, Res.get("dao.factsAndFigures.transactions.txDetails"), Layout.GROUP_DISTANCE);
|
||||
titledGroupBg.getStyleClass().add("last");
|
||||
|
||||
allTxTextField = addTopLabelReadOnlyTextField(root, gridRow, Res.get("dao.factsAndFigures.transactions.allTx"),
|
||||
genTxHeight, Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
||||
utxoTextField = addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.factsAndFigures.transactions.utxo")).second;
|
||||
compensationIssuanceTxTextField = addTopLabelReadOnlyTextField(root, ++gridRow,
|
||||
Res.get("dao.factsAndFigures.transactions.compensationIssuanceTx")).second;
|
||||
|
||||
int columnIndex = 1;
|
||||
|
||||
gridRow = startRow;
|
||||
|
||||
titledGroupBg = addTitledGroupBg(root, startRow, columnIndex, 3, "", Layout.GROUP_DISTANCE);
|
||||
titledGroupBg.getStyleClass().add("last");
|
||||
|
||||
reimbursementIssuanceTxTextField = addTopLabelReadOnlyTextField(root, gridRow, columnIndex,
|
||||
Res.get("dao.factsAndFigures.transactions.reimbursementIssuanceTx"),
|
||||
Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
||||
burntTxTextField = addTopLabelReadOnlyTextField(root, ++gridRow, columnIndex,
|
||||
Res.get("dao.factsAndFigures.transactions.burntTx")).second;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
daoFacade.addBsqStateListener(this);
|
||||
|
||||
updateWithBsqBlockChainData();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
daoFacade.removeBsqStateListener(this);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DaoStateListener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onParseBlockCompleteAfterBatchProcessing(Block block) {
|
||||
updateWithBsqBlockChainData();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void updateWithBsqBlockChainData() {
|
||||
allTxTextField.setText(String.valueOf(daoFacade.getTxs().size()));
|
||||
utxoTextField.setText(String.valueOf(daoFacade.getUnspentTxOutputs().size()));
|
||||
compensationIssuanceTxTextField.setText(String.valueOf(daoFacade.getNumIssuanceTransactions(IssuanceType.COMPENSATION)));
|
||||
reimbursementIssuanceTxTextField.setText(String.valueOf(daoFacade.getNumIssuanceTransactions(IssuanceType.REIMBURSEMENT)));
|
||||
burntTxTextField.setText(String.valueOf(daoFacade.getFeeTxs().size()));
|
||||
}
|
||||
}
|
||||
|
@ -336,7 +336,7 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
|
||||
areaChart.setId("charts");
|
||||
areaChart.setMinHeight(300);
|
||||
areaChart.setPrefHeight(300);
|
||||
areaChart.setCreateSymbols(false);
|
||||
areaChart.setCreateSymbols(true);
|
||||
areaChart.setPadding(new Insets(0, 10, 0, 10));
|
||||
areaChart.getData().addAll(seriesBuy, seriesSell);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user