mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-20 10:22:18 +01:00
Add unlock functionality
This commit is contained in:
parent
3ac0d225ef
commit
d5d7ea8e7e
@ -28,6 +28,7 @@ import bisq.desktop.components.MenuItem;
|
||||
import bisq.desktop.main.MainView;
|
||||
import bisq.desktop.main.dao.DaoView;
|
||||
import bisq.desktop.main.dao.bonding.Lock.LockupBSQView;
|
||||
import bisq.desktop.main.dao.bonding.unlock.UnlockBSQView;
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
|
||||
@ -51,6 +52,7 @@ public class BondingView extends ActivatableViewAndModel {
|
||||
private final Navigation navigation;
|
||||
|
||||
private MenuItem lockupBSQ;
|
||||
private MenuItem unlockBSQ;
|
||||
private Navigation.Listener listener;
|
||||
|
||||
@FXML
|
||||
@ -80,11 +82,16 @@ public class BondingView extends ActivatableViewAndModel {
|
||||
final List<Class<? extends View>> baseNavPath = Arrays.asList(MainView.class, DaoView.class, bisq.desktop.main.dao.bonding.BondingView.class);
|
||||
lockupBSQ = new MenuItem(navigation, toggleGroup, Res.get("dao.bonding.menuItem.lockupBSQ"),
|
||||
LockupBSQView.class, AwesomeIcon.LIST_UL, baseNavPath);
|
||||
leftVBox.getChildren().addAll(lockupBSQ);
|
||||
unlockBSQ = new MenuItem(navigation, toggleGroup, Res.get("dao.bonding.menuItem.unlockBSQ"),
|
||||
UnlockBSQView.class, AwesomeIcon.LIST_UL, baseNavPath);
|
||||
leftVBox.getChildren().addAll(lockupBSQ, unlockBSQ);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
lockupBSQ.activate();
|
||||
unlockBSQ.activate();
|
||||
|
||||
navigation.addListener(listener);
|
||||
ViewPath viewPath = navigation.getCurrentPath();
|
||||
if (viewPath.size() == 3 && viewPath.indexOf(BondingView.class) == 2 ||
|
||||
@ -105,6 +112,7 @@ public class BondingView extends ActivatableViewAndModel {
|
||||
navigation.removeListener(listener);
|
||||
|
||||
lockupBSQ.deactivate();
|
||||
unlockBSQ.deactivate();
|
||||
}
|
||||
|
||||
private void loadView(Class<? extends View> viewClass) {
|
||||
@ -112,9 +120,6 @@ public class BondingView extends ActivatableViewAndModel {
|
||||
content.getChildren().setAll(view.getRoot());
|
||||
|
||||
if (view instanceof LockupBSQView) lockupBSQ.setSelected(true);
|
||||
}
|
||||
|
||||
public Class<? extends View> getSelectedViewClass() {
|
||||
return selectedViewClass;
|
||||
else if (view instanceof UnlockBSQView) unlockBSQ.setSelected(true);
|
||||
}
|
||||
}
|
||||
|
@ -37,23 +37,17 @@ import bisq.core.btc.Restrictions;
|
||||
import bisq.core.btc.wallet.BsqBalanceListener;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.btc.wallet.TxBroadcastException;
|
||||
import bisq.core.btc.wallet.TxBroadcastTimeoutException;
|
||||
import bisq.core.btc.wallet.TxBroadcaster;
|
||||
import bisq.core.btc.wallet.TxMalleabilityException;
|
||||
import bisq.core.btc.wallet.WalletsManager;
|
||||
import bisq.core.btc.wallet.WalletsSetup;
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.voting.proposal.param.Param;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.util.CoinUtil;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@ -131,14 +125,14 @@ public class LockupBSQView extends ActivatableView<GridPane, Void> implements Bs
|
||||
focusOutListener = (observable, oldValue, newValue) -> {
|
||||
if (!newValue)
|
||||
onUpdateBalances(bsqWalletService.getAvailableBalance(), bsqWalletService.getPendingBalance(),
|
||||
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance());
|
||||
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance(),
|
||||
bsqWalletService.getUnlockingBondsBalance());
|
||||
};
|
||||
|
||||
lockupButton = addButtonAfterGroup(root, ++gridRow, Res.get("dao.bonding.lock.lockupButton"));
|
||||
|
||||
lockupButton.setOnAction((event) -> {
|
||||
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
|
||||
Address lockupAddress = bsqWalletService.getUnusedAddress();
|
||||
Coin lockupAmount = bsqFormatter.parseToCoin(amountInputTextField.getText());
|
||||
int lockupTime = Integer.parseInt(timeInputTextField.getText());
|
||||
try {
|
||||
@ -187,7 +181,8 @@ public class LockupBSQView extends ActivatableView<GridPane, Void> implements Bs
|
||||
amountInputTextField.focusedProperty().addListener(focusOutListener);
|
||||
bsqWalletService.addBsqBalanceListener(this);
|
||||
onUpdateBalances(bsqWalletService.getAvailableBalance(), bsqWalletService.getPendingBalance(),
|
||||
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance());
|
||||
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance(),
|
||||
bsqWalletService.getUnlockingBondsBalance());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -201,7 +196,8 @@ public class LockupBSQView extends ActivatableView<GridPane, Void> implements Bs
|
||||
public void onUpdateBalances(Coin confirmedBalance,
|
||||
Coin pendingBalance,
|
||||
Coin lockedForVotingBalance,
|
||||
Coin lockedInBondsBalance) {
|
||||
Coin lockedInBondsBalance,
|
||||
Coin unlockingBondsBalance) {
|
||||
bsqValidator.setAvailableBalance(confirmedBalance);
|
||||
boolean isValid = bsqValidator.validate(amountInputTextField.getText()).isValid;
|
||||
lockupButton.setDisable(!isValid);
|
||||
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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.bonding.unlock;
|
||||
|
||||
import bisq.desktop.components.AutoTooltipButton;
|
||||
import bisq.desktop.components.indicator.TxConfidenceIndicator;
|
||||
import bisq.desktop.util.BsqFormatter;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.btc.listeners.TxConfidenceListener;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.state.StateService;
|
||||
import bisq.core.dao.state.blockchain.TxType;
|
||||
import bisq.core.locale.Res;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.TransactionConfidence;
|
||||
|
||||
import javafx.scene.control.Tooltip;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@Data
|
||||
class LockedBsqTxListItem {
|
||||
private final Transaction transaction;
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final DaoFacade daoFacade;
|
||||
private final StateService stateService;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
private final Date date;
|
||||
private final String txId;
|
||||
|
||||
private int confirmations = 0;
|
||||
private Coin amount;
|
||||
private int lockTime;
|
||||
private AutoTooltipButton button;
|
||||
|
||||
private TxConfidenceIndicator txConfidenceIndicator;
|
||||
private TxConfidenceListener txConfidenceListener;
|
||||
private boolean issuanceTx;
|
||||
|
||||
LockedBsqTxListItem(Transaction transaction,
|
||||
BsqWalletService bsqWalletService,
|
||||
BtcWalletService btcWalletService,
|
||||
DaoFacade daoFacade,
|
||||
StateService stateService,
|
||||
Date date,
|
||||
BsqFormatter bsqFormatter) {
|
||||
this.transaction = transaction;
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.daoFacade = daoFacade;
|
||||
this.stateService = stateService;
|
||||
this.date = date;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
|
||||
txId = transaction.getHashAsString();
|
||||
|
||||
setupConfidence(bsqWalletService);
|
||||
|
||||
checkNotNull(transaction, "transaction must not be null as we only have list items from transactions " +
|
||||
"which are available in the wallet");
|
||||
|
||||
amount = bsqWalletService.getValueLockedUpInBond(transaction);
|
||||
|
||||
Optional<Integer> opLockTime = stateService.getLockTime(transaction.getHashAsString());
|
||||
lockTime = opLockTime.isPresent() ? opLockTime.get() : -1;
|
||||
|
||||
button = new AutoTooltipButton();
|
||||
button.setMinWidth(70);
|
||||
button.setText(Res.get("dao.bonding.unlock.unlock"));
|
||||
button.setVisible(true);
|
||||
button.setManaged(true);
|
||||
}
|
||||
|
||||
private void setupConfidence(BsqWalletService bsqWalletService) {
|
||||
txConfidenceIndicator = new TxConfidenceIndicator();
|
||||
txConfidenceIndicator.setId("funds-confidence");
|
||||
Tooltip tooltip = new Tooltip();
|
||||
txConfidenceIndicator.setProgress(0);
|
||||
txConfidenceIndicator.setPrefSize(24, 24);
|
||||
txConfidenceIndicator.setTooltip(tooltip);
|
||||
|
||||
txConfidenceListener = new TxConfidenceListener(txId) {
|
||||
@Override
|
||||
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
|
||||
updateConfidence(confidence, tooltip);
|
||||
}
|
||||
};
|
||||
bsqWalletService.addTxConfidenceListener(txConfidenceListener);
|
||||
updateConfidence(bsqWalletService.getConfidenceForTxId(txId), tooltip);
|
||||
}
|
||||
|
||||
private void updateConfidence(TransactionConfidence confidence, Tooltip tooltip) {
|
||||
if (confidence != null) {
|
||||
GUIUtil.updateConfidence(confidence, tooltip, txConfidenceIndicator);
|
||||
confirmations = confidence.getDepthInBlocks();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLocked() {
|
||||
return getTxType() == TxType.LOCK_UP;
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
bsqWalletService.removeTxConfidenceListener(txConfidenceListener);
|
||||
}
|
||||
|
||||
public TxType getTxType() {
|
||||
return daoFacade.getTx(txId)
|
||||
.flatMap(tx -> daoFacade.getTxType(tx.getId()))
|
||||
.orElse(confirmations == 0 ? TxType.UNVERIFIED : TxType.UNDEFINED_TX_TYPE);
|
||||
}
|
||||
|
||||
public void setAmount(Coin amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
<?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.bonding.unlock.UnlockBSQView"
|
||||
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
|
||||
AnchorPane.rightAnchor="0" AnchorPane.topAnchor="0.0"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" halignment="RIGHT" minWidth="160.0"/>
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
|
||||
</columnConstraints>
|
||||
</GridPane>
|
@ -0,0 +1,462 @@
|
||||
/*
|
||||
* 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.bonding.unlock;
|
||||
|
||||
import bisq.desktop.Navigation;
|
||||
import bisq.desktop.common.view.ActivatableView;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.AutoTooltipTableColumn;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.main.MainView;
|
||||
import bisq.desktop.main.dao.wallet.BsqBalanceUtil;
|
||||
import bisq.desktop.main.funds.FundsView;
|
||||
import bisq.desktop.main.funds.deposit.DepositView;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.util.BsqFormatter;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
import bisq.desktop.util.validation.BsqValidator;
|
||||
|
||||
import bisq.core.btc.wallet.BsqBalanceListener;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.btc.wallet.WalletsSetup;
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.state.BlockListener;
|
||||
import bisq.core.dao.state.StateService;
|
||||
import bisq.core.dao.state.blockchain.Block;
|
||||
import bisq.core.dao.state.blockchain.Tx;
|
||||
import bisq.core.dao.state.blockchain.TxOutput;
|
||||
import bisq.core.dao.state.blockchain.TxType;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.user.Preferences;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@FxmlView
|
||||
public class UnlockBSQView extends ActivatableView<GridPane, Void> implements BsqBalanceListener, BlockListener {
|
||||
private TableView<LockedBsqTxListItem> tableView;
|
||||
private Pane rootParent;
|
||||
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
private final BsqBalanceUtil bsqBalanceUtil;
|
||||
private final BsqValidator bsqValidator;
|
||||
private final DaoFacade daoFacade;
|
||||
private final Preferences preferences;
|
||||
private final StateService stateService;
|
||||
private final WalletsSetup walletsSetup;
|
||||
private final P2PService p2PService;
|
||||
private final Navigation navigation;
|
||||
|
||||
private int gridRow = 0;
|
||||
private boolean synched;
|
||||
private LockedBsqTxListItem selectedItem;
|
||||
|
||||
private final ObservableList<LockedBsqTxListItem> observableList = FXCollections.observableArrayList();
|
||||
private final FilteredList<LockedBsqTxListItem> lockedTxs = new FilteredList<>(observableList);
|
||||
|
||||
private ListChangeListener<Transaction> walletBsqTransactionsListener;
|
||||
private ChangeListener<Number> walletChainHeightListener;
|
||||
private final DoubleProperty initialOccupiedHeight = new SimpleDoubleProperty(-1);
|
||||
private ChangeListener<Number> parentHeightListener;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private UnlockBSQView(BsqWalletService bsqWalletService,
|
||||
BtcWalletService btcWalletService,
|
||||
BsqFormatter bsqFormatter,
|
||||
BsqBalanceUtil bsqBalanceUtil,
|
||||
BsqValidator bsqValidator,
|
||||
DaoFacade daoFacade,
|
||||
Preferences preferences,
|
||||
StateService stateService,
|
||||
WalletsSetup walletsSetup,
|
||||
P2PService p2PService,
|
||||
Navigation navigation) {
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
this.bsqBalanceUtil = bsqBalanceUtil;
|
||||
this.bsqValidator = bsqValidator;
|
||||
this.daoFacade = daoFacade;
|
||||
this.preferences = preferences;
|
||||
this.stateService = stateService;
|
||||
this.walletsSetup = walletsSetup;
|
||||
this.p2PService = p2PService;
|
||||
this.navigation = navigation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
// TODO: Show balance locked up in bonds
|
||||
gridRow = bsqBalanceUtil.addGroup(root, gridRow);
|
||||
|
||||
tableView = new TableView<>();
|
||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
addTxIdColumn();
|
||||
addAmountColumn();
|
||||
addLockTimeColumn();
|
||||
addUnlockColumn();
|
||||
|
||||
lockedTxs.setPredicate(item -> item.isLocked());
|
||||
walletBsqTransactionsListener = change -> updateList();
|
||||
walletChainHeightListener = (observable, oldValue, newValue) -> onUpdateAnyChainHeight();
|
||||
parentHeightListener = (observable, oldValue, newValue) -> layout();
|
||||
|
||||
VBox vBox = new VBox();
|
||||
vBox.setSpacing(10);
|
||||
GridPane.setRowIndex(vBox, ++gridRow);
|
||||
GridPane.setColumnSpan(vBox, 2);
|
||||
GridPane.setMargin(vBox, new Insets(40, -10, 5, -10));
|
||||
vBox.getChildren().addAll(tableView);
|
||||
root.getChildren().add(vBox);
|
||||
|
||||
}
|
||||
|
||||
private void addTxIdColumn() {
|
||||
TableColumn<LockedBsqTxListItem, LockedBsqTxListItem> column = new AutoTooltipTableColumn<>(Res.get("shared.txId"));
|
||||
|
||||
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
column.setMinWidth(60);
|
||||
column.setCellFactory(
|
||||
new Callback<TableColumn<LockedBsqTxListItem, LockedBsqTxListItem>, TableCell<LockedBsqTxListItem,
|
||||
LockedBsqTxListItem>>() {
|
||||
|
||||
@Override
|
||||
public TableCell<LockedBsqTxListItem, LockedBsqTxListItem> call(TableColumn<LockedBsqTxListItem,
|
||||
LockedBsqTxListItem> column) {
|
||||
return new TableCell<LockedBsqTxListItem, LockedBsqTxListItem>() {
|
||||
private HyperlinkWithIcon hyperlinkWithIcon;
|
||||
|
||||
@Override
|
||||
public void updateItem(final LockedBsqTxListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null && !empty) {
|
||||
String transactionId = item.getTxId();
|
||||
hyperlinkWithIcon = new HyperlinkWithIcon(transactionId, AwesomeIcon.EXTERNAL_LINK);
|
||||
hyperlinkWithIcon.setOnAction(event -> openTxInBlockExplorer(item));
|
||||
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", transactionId)));
|
||||
setGraphic(hyperlinkWithIcon);
|
||||
} else {
|
||||
setGraphic(null);
|
||||
if (hyperlinkWithIcon != null)
|
||||
hyperlinkWithIcon.setOnAction(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
tableView.getColumns().add(column);
|
||||
}
|
||||
|
||||
private void addAmountColumn() {
|
||||
TableColumn<LockedBsqTxListItem, LockedBsqTxListItem> column =
|
||||
new AutoTooltipTableColumn<>(Res.get("shared.amountWithCur", "BSQ"));
|
||||
column.setMinWidth(120);
|
||||
column.setMaxWidth(column.getMinWidth());
|
||||
|
||||
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
column.setCellFactory(new Callback<TableColumn<LockedBsqTxListItem, LockedBsqTxListItem>,
|
||||
TableCell<LockedBsqTxListItem, LockedBsqTxListItem>>() {
|
||||
|
||||
@Override
|
||||
public TableCell<LockedBsqTxListItem, LockedBsqTxListItem> call(TableColumn<LockedBsqTxListItem,
|
||||
LockedBsqTxListItem> column) {
|
||||
return new TableCell<LockedBsqTxListItem, LockedBsqTxListItem>() {
|
||||
|
||||
@Override
|
||||
public void updateItem(final LockedBsqTxListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty) {
|
||||
TxType txType = item.getTxType();
|
||||
setText(item.getConfirmations() > 0 && txType.ordinal() > TxType.INVALID.ordinal() ?
|
||||
bsqFormatter.formatCoin(item.getAmount()) :
|
||||
Res.get("shared.na"));
|
||||
} else
|
||||
setText("");
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
tableView.getColumns().add(column);
|
||||
}
|
||||
|
||||
private void addLockTimeColumn() {
|
||||
TableColumn<LockedBsqTxListItem, LockedBsqTxListItem> column =
|
||||
new AutoTooltipTableColumn<>(Res.get("dao.bonding.unlock.time"));
|
||||
column.setMinWidth(120);
|
||||
column.setMaxWidth(column.getMinWidth());
|
||||
|
||||
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
column.setCellFactory(new Callback<TableColumn<LockedBsqTxListItem, LockedBsqTxListItem>,
|
||||
TableCell<LockedBsqTxListItem, LockedBsqTxListItem>>() {
|
||||
|
||||
@Override
|
||||
public TableCell<LockedBsqTxListItem, LockedBsqTxListItem> call(TableColumn<LockedBsqTxListItem,
|
||||
LockedBsqTxListItem> column) {
|
||||
return new TableCell<LockedBsqTxListItem, LockedBsqTxListItem>() {
|
||||
|
||||
@Override
|
||||
public void updateItem(final LockedBsqTxListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty) {
|
||||
TxType txType = item.getTxType();
|
||||
setText(item.getConfirmations() > 0 && txType.ordinal() > TxType.INVALID.ordinal() ?
|
||||
Integer.toString(item.getLockTime()) :
|
||||
Res.get("shared.na"));
|
||||
} else
|
||||
setText("");
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
tableView.getColumns().add(column);
|
||||
}
|
||||
|
||||
private void addUnlockColumn() {
|
||||
TableColumn<LockedBsqTxListItem, LockedBsqTxListItem> unlockColumn = new TableColumn<>();
|
||||
unlockColumn.setMinWidth(130);
|
||||
unlockColumn.setMaxWidth(unlockColumn.getMinWidth());
|
||||
|
||||
unlockColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
|
||||
unlockColumn.setCellFactory(new Callback<TableColumn<LockedBsqTxListItem, LockedBsqTxListItem>,
|
||||
TableCell<LockedBsqTxListItem, LockedBsqTxListItem>>() {
|
||||
|
||||
@Override
|
||||
public TableCell<LockedBsqTxListItem, LockedBsqTxListItem> call(TableColumn<LockedBsqTxListItem,
|
||||
LockedBsqTxListItem> column) {
|
||||
return new TableCell<LockedBsqTxListItem, LockedBsqTxListItem>() {
|
||||
Button button;
|
||||
|
||||
@Override
|
||||
public void updateItem(final LockedBsqTxListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null && !empty) {
|
||||
if (button == null) {
|
||||
button = item.getButton();
|
||||
button.setOnAction(e -> {
|
||||
UnlockBSQView.this.selectedItem = item;
|
||||
UnlockBSQView.this.onButtonClick();
|
||||
});
|
||||
setGraphic(button);
|
||||
}
|
||||
} else {
|
||||
setGraphic(null);
|
||||
if (button != null) {
|
||||
button.setOnAction(null);
|
||||
button = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
unlockColumn.setComparator(Comparator.comparing(LockedBsqTxListItem::getConfirmations));
|
||||
tableView.getColumns().add(unlockColumn);
|
||||
}
|
||||
|
||||
private void onButtonClick() {
|
||||
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
|
||||
Optional<TxOutput> lockedTxOutput = stateService.getLockedTxOutput(selectedItem.getTxId());
|
||||
if (!lockedTxOutput.isPresent()) {
|
||||
log.warn("Locked output not found, txId = ", selectedItem.getTxId());
|
||||
return;
|
||||
}
|
||||
|
||||
Coin unlockAmount = Coin.valueOf(lockedTxOutput.get().getValue());
|
||||
Optional<Integer> opLockTime = stateService.getLockTime(lockedTxOutput.get());
|
||||
int lockTime = opLockTime.isPresent() ? opLockTime.get() : -1;
|
||||
|
||||
try {
|
||||
new Popup<>().headLine(Res.get("dao.bonding.unlock.sendTx.headline"))
|
||||
.confirmation(Res.get("dao.bonding.unlock.sendTx.details",
|
||||
bsqFormatter.formatCoinWithCode(unlockAmount),
|
||||
lockTime
|
||||
))
|
||||
.actionButtonText(Res.get("shared.yes"))
|
||||
.onAction(() -> {
|
||||
daoFacade.publishUnlockTx(selectedItem.getTxId(),
|
||||
() -> {
|
||||
new Popup<>().confirmation(Res.get("dao.tx.published.success")).show();
|
||||
},
|
||||
errorMessage -> new Popup<>().warning(errorMessage.toString()).show()
|
||||
);
|
||||
})
|
||||
.closeButtonText(Res.get("shared.cancel"))
|
||||
.show();
|
||||
} catch (Throwable t) {
|
||||
if (t instanceof InsufficientMoneyException) {
|
||||
final Coin missingCoin = ((InsufficientMoneyException) t).missing;
|
||||
final String missing = missingCoin != null ? missingCoin.toFriendlyString() : "null";
|
||||
//noinspection unchecked
|
||||
new Popup<>().warning(Res.get("popup.warning.insufficientBtcFundsForBsqTx", missing))
|
||||
.actionButtonTextWithGoTo("navigation.funds.depositFunds")
|
||||
.onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, DepositView.class))
|
||||
.show();
|
||||
} else {
|
||||
log.error(t.toString());
|
||||
t.printStackTrace();
|
||||
new Popup<>().warning(t.getMessage()).show();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GUIUtil.showNotReadyForTxBroadcastPopups(p2PService, walletsSetup);
|
||||
}
|
||||
log.info("unlock tx: {}", selectedItem.getTxId());
|
||||
}
|
||||
|
||||
private void openTxInBlockExplorer(LockedBsqTxListItem item) {
|
||||
if (item.getTxId() != null)
|
||||
GUIUtil.openWebPage(preferences.getBsqBlockChainExplorer().txUrl + item.getTxId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
bsqBalanceUtil.activate();
|
||||
bsqWalletService.addBsqBalanceListener(this);
|
||||
onUpdateBalances(bsqWalletService.getAvailableBalance(), bsqWalletService.getPendingBalance(),
|
||||
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance(),
|
||||
bsqWalletService.getUnlockingBondsBalance());
|
||||
|
||||
bsqWalletService.getWalletTransactions().addListener(walletBsqTransactionsListener);
|
||||
bsqWalletService.addBsqBalanceListener(this);
|
||||
btcWalletService.getChainHeightProperty().addListener(walletChainHeightListener);
|
||||
|
||||
tableView.setItems(lockedTxs);
|
||||
|
||||
daoFacade.addBlockListener(this);
|
||||
|
||||
if (root.getParent() instanceof Pane) {
|
||||
rootParent = (Pane) root.getParent();
|
||||
rootParent.heightProperty().addListener(parentHeightListener);
|
||||
}
|
||||
|
||||
updateList();
|
||||
onUpdateAnyChainHeight();
|
||||
layout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockAdded(Block block) {
|
||||
onUpdateAnyChainHeight();
|
||||
}
|
||||
|
||||
private void onUpdateAnyChainHeight() {
|
||||
final int bsqBlockChainHeight = daoFacade.getChainHeight();
|
||||
final int bsqWalletChainHeight = bsqWalletService.getBestChainHeight();
|
||||
if (bsqWalletChainHeight > 0) {
|
||||
synched = bsqWalletChainHeight == bsqBlockChainHeight;
|
||||
}
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
observableList.forEach(LockedBsqTxListItem::cleanup);
|
||||
|
||||
// copy list to avoid ConcurrentModificationException
|
||||
final List<Transaction> walletTransactions = new ArrayList<>(bsqWalletService.getWalletTransactions());
|
||||
List<LockedBsqTxListItem> items = walletTransactions.stream()
|
||||
.map(transaction -> {
|
||||
return new LockedBsqTxListItem(transaction,
|
||||
bsqWalletService,
|
||||
btcWalletService,
|
||||
daoFacade,
|
||||
stateService,
|
||||
transaction.getUpdateTime(),
|
||||
bsqFormatter);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
observableList.setAll(items);
|
||||
}
|
||||
|
||||
private void layout() {
|
||||
GUIUtil.fillAvailableHeight(root, tableView, initialOccupiedHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
bsqBalanceUtil.deactivate();
|
||||
bsqWalletService.removeBsqBalanceListener(this);
|
||||
|
||||
|
||||
bsqBalanceUtil.deactivate();
|
||||
lockedTxs.predicateProperty().unbind();
|
||||
bsqWalletService.getWalletTransactions().removeListener(walletBsqTransactionsListener);
|
||||
bsqWalletService.removeBsqBalanceListener(this);
|
||||
btcWalletService.getChainHeightProperty().removeListener(walletChainHeightListener);
|
||||
daoFacade.removeBlockListener(this);
|
||||
|
||||
observableList.forEach(LockedBsqTxListItem::cleanup);
|
||||
|
||||
if (rootParent != null)
|
||||
rootParent.heightProperty().removeListener(parentHeightListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateBalances(Coin confirmedBalance,
|
||||
Coin pendingBalance,
|
||||
Coin lockedForVotingBalance,
|
||||
Coin lockedInBondsBalance,
|
||||
Coin unlockingBondsBalance) {
|
||||
bsqValidator.setAvailableBalance(confirmedBalance);
|
||||
}
|
||||
}
|
@ -114,7 +114,8 @@ public class ActiveBallotsView extends BaseProposalView implements BsqBalanceLis
|
||||
onUpdateBalances(bsqWalletService.getAvailableBalance(),
|
||||
bsqWalletService.getPendingBalance(),
|
||||
bsqWalletService.getLockedForVotingBalance(),
|
||||
bsqWalletService.getLockedInBondsBalance());
|
||||
bsqWalletService.getLockedInBondsBalance(),
|
||||
bsqWalletService.getUnlockingBondsBalance());
|
||||
|
||||
voteButton.setOnAction(e -> onVote());
|
||||
|
||||
@ -141,7 +142,8 @@ public class ActiveBallotsView extends BaseProposalView implements BsqBalanceLis
|
||||
public void onUpdateBalances(Coin confirmedBalance,
|
||||
Coin pendingBalance,
|
||||
Coin lockedForVotingBalance,
|
||||
Coin lockedInBondsBalance) {
|
||||
Coin lockedInBondsBalance,
|
||||
Coin unlockingBondsBalance) {
|
||||
stakeInputTextField.setPromptText(Res.get("dao.proposal.myVote.stake.prompt",
|
||||
bsqFormatter.formatCoinWithCode(confirmedBalance)));
|
||||
}
|
||||
|
@ -83,7 +83,8 @@ public class BsqBalanceUtil implements BsqBalanceListener {
|
||||
onUpdateBalances(bsqWalletService.getAvailableBalance(),
|
||||
bsqWalletService.getPendingBalance(),
|
||||
bsqWalletService.getLockedForVotingBalance(),
|
||||
bsqWalletService.getLockedInBondsBalance());
|
||||
bsqWalletService.getLockedInBondsBalance(),
|
||||
bsqWalletService.getUnlockingBondsBalance());
|
||||
bsqWalletService.addBsqBalanceListener(this);
|
||||
}
|
||||
|
||||
@ -96,11 +97,16 @@ public class BsqBalanceUtil implements BsqBalanceListener {
|
||||
public void onUpdateBalances(Coin confirmedBalance,
|
||||
Coin pendingBalance,
|
||||
Coin lockedForVotingBalance,
|
||||
Coin lockedInBondsBalance) {
|
||||
Coin lockedInBondsBalance,
|
||||
Coin unlockingBondsBalance) {
|
||||
confirmedBalanceTextField.setText(bsqFormatter.formatCoinWithCode(confirmedBalance));
|
||||
pendingBalanceTextField.setText(bsqFormatter.formatCoinWithCode(pendingBalance));
|
||||
lockedForVoteBalanceTextField.setText(bsqFormatter.formatCoinWithCode(lockedForVotingBalance));
|
||||
final Coin total = confirmedBalance.add(pendingBalance).add(lockedForVotingBalance).add(lockedInBondsBalance);
|
||||
final Coin total = confirmedBalance
|
||||
.add(pendingBalance)
|
||||
.add(lockedForVotingBalance)
|
||||
.add(lockedInBondsBalance)
|
||||
.add(unlockingBondsBalance);
|
||||
totalBalanceTextField.setText(bsqFormatter.formatCoinWithCode(total));
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +131,8 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
|
||||
focusOutListener = (observable, oldValue, newValue) -> {
|
||||
if (!newValue)
|
||||
onUpdateBalances(bsqWalletService.getAvailableBalance(), bsqWalletService.getPendingBalance(),
|
||||
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance());
|
||||
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance(),
|
||||
bsqWalletService.getUnlockingBondsBalance());
|
||||
};
|
||||
|
||||
sendButton = addButtonAfterGroup(root, ++gridRow, Res.get("dao.wallet.send.send"));
|
||||
@ -215,7 +216,8 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
|
||||
amountInputTextField.focusedProperty().addListener(focusOutListener);
|
||||
bsqWalletService.addBsqBalanceListener(this);
|
||||
onUpdateBalances(bsqWalletService.getAvailableBalance(), bsqWalletService.getPendingBalance(),
|
||||
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance());
|
||||
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance(),
|
||||
bsqWalletService.getUnlockingBondsBalance());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -230,7 +232,8 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
|
||||
public void onUpdateBalances(Coin confirmedBalance,
|
||||
Coin pendingBalance,
|
||||
Coin lockedForVotingBalance,
|
||||
Coin lockedInBondsBalance) {
|
||||
Coin lockedInBondsBalance,
|
||||
Coin unlockingBondsBalance) {
|
||||
bsqValidator.setAvailableBalance(confirmedBalance);
|
||||
boolean isValid = bsqAddressValidator.validate(receiversAddressInputTextField.getText()).isValid &&
|
||||
bsqValidator.validate(amountInputTextField.getText()).isValid;
|
||||
|
@ -208,7 +208,8 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
|
||||
public void onUpdateBalances(Coin confirmedBalance,
|
||||
Coin pendingBalance,
|
||||
Coin lockedForVotingBalance,
|
||||
Coin lockedInBondsBalance) {
|
||||
Coin lockedInBondsBalance,
|
||||
Coin unlockingBondsBalance) {
|
||||
updateList();
|
||||
}
|
||||
|
||||
|
@ -539,7 +539,8 @@ public abstract class EditableOfferDataModel extends OfferDataModel implements B
|
||||
public void onUpdateBalances(Coin confirmedBalance,
|
||||
Coin pendingBalance,
|
||||
Coin lockedForVotingBalance,
|
||||
Coin lockedInBondsBalance) {
|
||||
Coin lockedInBondsBalance,
|
||||
Coin unlockingBondsBalance) {
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user