mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 07:07:43 +01:00
Add combined proposal vote view (WIP)
This commit is contained in:
parent
149c5a2fc0
commit
af614dfeff
4 changed files with 763 additions and 2 deletions
|
@ -31,6 +31,7 @@ import bisq.desktop.main.dao.proposal.active.ActiveProposalsView;
|
|||
import bisq.desktop.main.dao.proposal.closed.ClosedProposalsView;
|
||||
import bisq.desktop.main.dao.proposal.dashboard.ProposalDashboardView;
|
||||
import bisq.desktop.main.dao.proposal.make.MakeProposalView;
|
||||
import bisq.desktop.main.dao.proposal.open.OpenProposalsView;
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
|
||||
|
@ -53,7 +54,7 @@ public class ProposalView extends ActivatableViewAndModel {
|
|||
private final ViewLoader viewLoader;
|
||||
private final Navigation navigation;
|
||||
|
||||
private MenuItem dashboard, make, active, closed;
|
||||
private MenuItem dashboard, make, open, active, closed;
|
||||
private Navigation.Listener listener;
|
||||
|
||||
@FXML
|
||||
|
@ -85,17 +86,20 @@ public class ProposalView extends ActivatableViewAndModel {
|
|||
ProposalDashboardView.class, AwesomeIcon.DASHBOARD, baseNavPath);
|
||||
make = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.make"),
|
||||
MakeProposalView.class, AwesomeIcon.EDIT, baseNavPath);
|
||||
open = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.open"),
|
||||
OpenProposalsView.class, AwesomeIcon.LIST_UL, baseNavPath);
|
||||
active = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.active"),
|
||||
ActiveProposalsView.class, AwesomeIcon.LIST_UL, baseNavPath);
|
||||
closed = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.closed"),
|
||||
ClosedProposalsView.class, AwesomeIcon.LIST_ALT, baseNavPath);
|
||||
leftVBox.getChildren().addAll(dashboard, make, active, closed);
|
||||
leftVBox.getChildren().addAll(dashboard, make, open, active, closed);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
dashboard.activate();
|
||||
make.activate();
|
||||
open.activate();
|
||||
active.activate();
|
||||
closed.activate();
|
||||
|
||||
|
@ -121,6 +125,7 @@ public class ProposalView extends ActivatableViewAndModel {
|
|||
|
||||
dashboard.deactivate();
|
||||
make.deactivate();
|
||||
open.deactivate();
|
||||
active.deactivate();
|
||||
closed.deactivate();
|
||||
}
|
||||
|
@ -131,6 +136,7 @@ public class ProposalView extends ActivatableViewAndModel {
|
|||
|
||||
if (view instanceof ProposalDashboardView) dashboard.setSelected(true);
|
||||
else if (view instanceof MakeProposalView) make.setSelected(true);
|
||||
else if (view instanceof OpenProposalsView) open.setSelected(true);
|
||||
else if (view instanceof ActiveProposalsView) active.setSelected(true);
|
||||
else if (view instanceof ClosedProposalsView) closed.setSelected(true);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* 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.proposal.open;
|
||||
|
||||
import bisq.desktop.components.AutoTooltipButton;
|
||||
import bisq.desktop.components.indicator.TxConfidenceIndicator;
|
||||
|
||||
import bisq.core.btc.listeners.TxConfidenceListener;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.state.BsqStateListener;
|
||||
import bisq.core.dao.state.blockchain.Block;
|
||||
import bisq.core.dao.state.blockchain.Tx;
|
||||
import bisq.core.dao.state.period.DaoPhase;
|
||||
import bisq.core.dao.voting.proposal.Proposal;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.util.BsqFormatter;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.TransactionConfidence;
|
||||
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.image.ImageView;
|
||||
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@ToString
|
||||
@Slf4j
|
||||
@EqualsAndHashCode
|
||||
public class OpenProposalListItem implements BsqStateListener {
|
||||
@Getter
|
||||
private final DaoFacade daoFacade;
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
@Getter
|
||||
private final Proposal proposal;
|
||||
|
||||
@Getter
|
||||
private ImageView imageView;
|
||||
@Getter
|
||||
private AutoTooltipButton button;
|
||||
|
||||
@Getter
|
||||
private TxConfidenceIndicator txConfidenceIndicator;
|
||||
@Getter
|
||||
private Integer confirmations = 0;
|
||||
private TxConfidenceListener txConfidenceListener;
|
||||
private Tooltip tooltip = new Tooltip(Res.get("confidence.unknown"));
|
||||
private Transaction walletTransaction;
|
||||
private ChangeListener<DaoPhase.Phase> phaseChangeListener;
|
||||
private ChangeListener<Number> chainHeightListener;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OpenProposalListItem(Proposal proposal,
|
||||
DaoFacade daoFacade,
|
||||
BsqWalletService bsqWalletService,
|
||||
BsqFormatter bsqFormatter) {
|
||||
this.daoFacade = daoFacade;
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
|
||||
this.proposal = proposal;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BsqStateListener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onNewBlockHeight(int blockHeight) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEmptyBlockAdded(Block block) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onParseTxsComplete(Block block) {
|
||||
setupConfidence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onParseBlockChainComplete() {
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void cleanup() {
|
||||
daoFacade.removeBsqStateListener(this);
|
||||
bsqWalletService.getChainHeightProperty().removeListener(chainHeightListener);
|
||||
if (txConfidenceListener != null)
|
||||
bsqWalletService.removeTxConfidenceListener(txConfidenceListener);
|
||||
|
||||
daoFacade.phaseProperty().removeListener(phaseChangeListener);
|
||||
}
|
||||
|
||||
public void onPhaseChanged(DaoPhase.Phase phase) {
|
||||
//noinspection IfCanBeSwitch
|
||||
if (phase == DaoPhase.Phase.PROPOSAL) {
|
||||
imageView.setId("image-remove");
|
||||
button.setGraphic(imageView);
|
||||
button.setText(Res.get("shared.remove"));
|
||||
final boolean isMyProposal = daoFacade.isMyProposal(proposal);
|
||||
button.setVisible(isMyProposal);
|
||||
button.setManaged(isMyProposal);
|
||||
} else if (phase == DaoPhase.Phase.BLIND_VOTE) {
|
||||
button.setGraphic(null);
|
||||
button.setText(Res.get("dao.proposal.active.vote"));
|
||||
button.setVisible(true);
|
||||
button.setManaged(true);
|
||||
} else {
|
||||
button.setVisible(false);
|
||||
button.setManaged(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void init() {
|
||||
txConfidenceIndicator = new TxConfidenceIndicator();
|
||||
txConfidenceIndicator.setId("funds-confidence");
|
||||
|
||||
txConfidenceIndicator.setProgress(-1);
|
||||
txConfidenceIndicator.setPrefSize(24, 24);
|
||||
txConfidenceIndicator.setTooltip(tooltip);
|
||||
|
||||
|
||||
imageView = new ImageView();
|
||||
|
||||
chainHeightListener = (observable, oldValue, newValue) -> setupConfidence();
|
||||
bsqWalletService.getChainHeightProperty().addListener(chainHeightListener);
|
||||
setupConfidence();
|
||||
|
||||
daoFacade.addBsqStateListener(this);
|
||||
|
||||
phaseChangeListener = (observable, oldValue, newValue) -> onPhaseChanged(newValue);
|
||||
|
||||
daoFacade.phaseProperty().addListener(phaseChangeListener);
|
||||
|
||||
button = new AutoTooltipButton();
|
||||
button.setMinWidth(70);
|
||||
onPhaseChanged(daoFacade.phaseProperty().get());
|
||||
}
|
||||
|
||||
private void setupConfidence() {
|
||||
final String txId = proposal.getTxId();
|
||||
Optional<Tx> optionalTx = daoFacade.getTx(txId);
|
||||
optionalTx.ifPresent(tx -> {
|
||||
// We cache the walletTransaction once found
|
||||
if (walletTransaction == null) {
|
||||
final Optional<Transaction> transactionOptional = bsqWalletService.isWalletTransaction(txId);
|
||||
transactionOptional.ifPresent(transaction -> walletTransaction = transaction);
|
||||
}
|
||||
|
||||
if (walletTransaction != null) {
|
||||
// It is our tx so we get confidence updates
|
||||
if (txConfidenceListener == null) {
|
||||
txConfidenceListener = new TxConfidenceListener(txId) {
|
||||
@Override
|
||||
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
|
||||
updateConfidence(confidence.getConfidenceType(), confidence.getDepthInBlocks(), confidence.numBroadcastPeers());
|
||||
}
|
||||
};
|
||||
bsqWalletService.addTxConfidenceListener(txConfidenceListener);
|
||||
}
|
||||
} else {
|
||||
// tx from other users, we don't get confidence updates but as we have the bsq tx we can calculate it
|
||||
// we get setupConfidence called at each new block from above listener so no need to register a new listener
|
||||
int depth = bsqWalletService.getChainHeightProperty().get() - tx.getBlockHeight() + 1;
|
||||
if (depth > 0)
|
||||
updateConfidence(TransactionConfidence.ConfidenceType.BUILDING, depth, -1);
|
||||
}
|
||||
|
||||
final TransactionConfidence confidence = bsqWalletService.getConfidenceForTxId(txId);
|
||||
if (confidence != null)
|
||||
updateConfidence(confidence, confidence.getDepthInBlocks());
|
||||
});
|
||||
}
|
||||
|
||||
private void updateConfidence(TransactionConfidence confidence, int depthInBlocks) {
|
||||
if (confidence != null) {
|
||||
updateConfidence(confidence.getConfidenceType(), confidence.getDepthInBlocks(), confidence.numBroadcastPeers());
|
||||
confirmations = depthInBlocks;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateConfidence(TransactionConfidence.ConfidenceType confidenceType, int depthInBlocks, int numBroadcastPeers) {
|
||||
switch (confidenceType) {
|
||||
case UNKNOWN:
|
||||
tooltip.setText(Res.get("confidence.unknown"));
|
||||
txConfidenceIndicator.setProgress(0);
|
||||
break;
|
||||
case PENDING:
|
||||
tooltip.setText(Res.get("confidence.seen", numBroadcastPeers > -1 ? numBroadcastPeers : Res.get("shared.na")));
|
||||
txConfidenceIndicator.setProgress(-1.0);
|
||||
break;
|
||||
case BUILDING:
|
||||
tooltip.setText(Res.get("confidence.confirmed", depthInBlocks));
|
||||
txConfidenceIndicator.setProgress(Math.min(1, (double) depthInBlocks / 6.0));
|
||||
break;
|
||||
case DEAD:
|
||||
tooltip.setText(Res.get("confidence.invalid"));
|
||||
txConfidenceIndicator.setProgress(0);
|
||||
break;
|
||||
}
|
||||
|
||||
txConfidenceIndicator.setPrefSize(24, 24);
|
||||
}
|
||||
}
|
|
@ -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.proposal.open.OpenProposalsView"
|
||||
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 hgrow="SOMETIMES" halignment="RIGHT" minWidth="160.0"/>
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
|
||||
</columnConstraints>
|
||||
</GridPane>
|
|
@ -0,0 +1,478 @@
|
|||
/*
|
||||
* 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.proposal.open;
|
||||
|
||||
import bisq.desktop.Navigation;
|
||||
import bisq.desktop.common.view.ActivatableView;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.AutoTooltipTableColumn;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.TableGroupHeadline;
|
||||
import bisq.desktop.main.MainView;
|
||||
import bisq.desktop.main.dao.DaoView;
|
||||
import bisq.desktop.main.dao.proposal.ProposalDisplay;
|
||||
import bisq.desktop.main.dao.proposal.ProposalWindow;
|
||||
import bisq.desktop.main.dao.voting.VotingView;
|
||||
import bisq.desktop.main.dao.voting.active.ActiveBallotsView;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.state.period.DaoPhase;
|
||||
import bisq.core.dao.voting.proposal.Proposal;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.util.BSFormatter;
|
||||
import bisq.core.util.BsqFormatter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
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.Priority;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
import org.fxmisc.easybind.Subscription;
|
||||
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static bisq.desktop.util.FormBuilder.addButtonAfterGroup;
|
||||
|
||||
@FxmlView
|
||||
public class OpenProposalsView extends ActivatableView<GridPane, Void> {
|
||||
|
||||
private final DaoFacade daoFacade;
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
private final BSFormatter btcFormatter;
|
||||
|
||||
private final ObservableList<OpenProposalListItem> proposalBaseProposalListItems = FXCollections.observableArrayList();
|
||||
private final SortedList<OpenProposalListItem> sortedList = new SortedList<>(proposalBaseProposalListItems);
|
||||
private TableView<OpenProposalListItem> proposalTableView;
|
||||
private Subscription selectedProposalSubscription;
|
||||
private ProposalDisplay proposalDisplay;
|
||||
private int gridRow = 0;
|
||||
private GridPane detailsGridPane, gridPane;
|
||||
private OpenProposalListItem selectedBaseProposalListItem;
|
||||
|
||||
private DaoPhase.Phase currentPhase;
|
||||
private Subscription phaseSubscription;
|
||||
private ScrollPane proposalDisplayView;
|
||||
private boolean proposalDisplayInitialized;
|
||||
|
||||
|
||||
private ListChangeListener<Proposal> listChangeListener;
|
||||
private final Navigation navigation;
|
||||
|
||||
private Button button;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private OpenProposalsView(DaoFacade daoFacade,
|
||||
BsqWalletService bsqWalletService,
|
||||
BsqFormatter bsqFormatter,
|
||||
BSFormatter btcFormatter,
|
||||
Navigation navigation) {
|
||||
|
||||
this.daoFacade = daoFacade;
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
this.btcFormatter = btcFormatter;
|
||||
this.navigation = navigation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
root.getStyleClass().add("vote-root");
|
||||
|
||||
detailsGridPane = new GridPane();
|
||||
createProposalsTableView();
|
||||
createEmptyProposalDisplay();
|
||||
|
||||
listChangeListener = c -> updateListItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
phaseSubscription = EasyBind.subscribe(daoFacade.phaseProperty(), this::onPhaseChanged);
|
||||
selectedProposalSubscription = EasyBind.subscribe(proposalTableView.getSelectionModel().selectedItemProperty(), this::onSelectProposal);
|
||||
|
||||
sortedList.comparatorProperty().bind(proposalTableView.comparatorProperty());
|
||||
|
||||
updateListItems();
|
||||
|
||||
getProposals().addListener(listChangeListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
phaseSubscription.unsubscribe();
|
||||
selectedProposalSubscription.unsubscribe();
|
||||
|
||||
sortedList.comparatorProperty().unbind();
|
||||
|
||||
proposalBaseProposalListItems.forEach(OpenProposalListItem::cleanup);
|
||||
proposalTableView.getSelectionModel().clearSelection();
|
||||
selectedBaseProposalListItem = null;
|
||||
|
||||
getProposals().removeListener(listChangeListener);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private ObservableList<Proposal> getProposals() {
|
||||
return daoFacade.getActiveOrMyUnconfirmedProposals();
|
||||
}
|
||||
|
||||
private void updateListItems() {
|
||||
proposalBaseProposalListItems.forEach(OpenProposalListItem::cleanup);
|
||||
proposalBaseProposalListItems.clear();
|
||||
|
||||
fillListItems();
|
||||
|
||||
if (proposalBaseProposalListItems.isEmpty())
|
||||
hideProposalDisplay();
|
||||
}
|
||||
|
||||
private void createAllFieldsOnProposalDisplay(Proposal proposal) {
|
||||
proposalDisplayView.setVisible(true);
|
||||
proposalDisplayView.setManaged(true);
|
||||
|
||||
proposalDisplay.createAllFields(Res.get("dao.proposal.selectedProposal"), 0, 0, proposal.getType(),
|
||||
false);
|
||||
proposalDisplay.setEditable(false);
|
||||
proposalDisplay.applyProposalPayload(proposal);
|
||||
proposalDisplayInitialized = true;
|
||||
|
||||
button = addButtonAfterGroup(detailsGridPane, proposalDisplay.incrementAndGetGridRow(), "");
|
||||
button.setOnAction(event -> onButtonClick());
|
||||
onPhaseChanged(daoFacade.phaseProperty().get());
|
||||
}
|
||||
|
||||
private void hideProposalDisplay() {
|
||||
if (proposalDisplayInitialized) {
|
||||
proposalDisplay.removeAllFields();
|
||||
proposalDisplayView.setVisible(false);
|
||||
proposalDisplayView.setManaged(false);
|
||||
}
|
||||
if (button != null) {
|
||||
button.setManaged(false);
|
||||
button.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillListItems() {
|
||||
List<Proposal> list = getProposals();
|
||||
proposalBaseProposalListItems.setAll(list.stream()
|
||||
.map(proposal -> new OpenProposalListItem(proposal, daoFacade, bsqWalletService, bsqFormatter))
|
||||
.collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
|
||||
private void onPhaseChanged(DaoPhase.Phase phase) {
|
||||
if (phase != null && !phase.equals(currentPhase)) {
|
||||
currentPhase = phase;
|
||||
onSelectProposal(selectedBaseProposalListItem);
|
||||
}
|
||||
|
||||
if (button != null) {
|
||||
//noinspection IfCanBeSwitch,IfCanBeSwitch,IfCanBeSwitch
|
||||
if (phase == DaoPhase.Phase.PROPOSAL) {
|
||||
if (selectedBaseProposalListItem != null && selectedBaseProposalListItem.getProposal() != null) {
|
||||
button.setText(Res.get("shared.remove"));
|
||||
final boolean isMyProposal = daoFacade.isMyProposal(selectedBaseProposalListItem.getProposal());
|
||||
button.setVisible(isMyProposal);
|
||||
button.setManaged(isMyProposal);
|
||||
}
|
||||
} else if (phase == DaoPhase.Phase.BLIND_VOTE) {
|
||||
button.setText(Res.get("dao.proposal.active.vote"));
|
||||
button.setVisible(true);
|
||||
button.setManaged(true);
|
||||
} else {
|
||||
button.setVisible(false);
|
||||
button.setManaged(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Handlers
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void onButtonClick() {
|
||||
if (daoFacade.phaseProperty().get() == DaoPhase.Phase.PROPOSAL) {
|
||||
final Proposal proposal = selectedBaseProposalListItem.getProposal();
|
||||
if (daoFacade.removeMyProposal(proposal)) {
|
||||
hideProposalDisplay();
|
||||
} else {
|
||||
new Popup<>().warning(Res.get("dao.proposal.active.remove.failed")).show();
|
||||
}
|
||||
proposalTableView.getSelectionModel().clearSelection();
|
||||
} else if (daoFacade.phaseProperty().get() == DaoPhase.Phase.BLIND_VOTE) {
|
||||
navigation.navigateTo(MainView.class, DaoView.class, VotingView.class, ActiveBallotsView.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void onSelectProposal(OpenProposalListItem item) {
|
||||
selectedBaseProposalListItem = item;
|
||||
if (selectedBaseProposalListItem != null)
|
||||
createAllFieldsOnProposalDisplay(selectedBaseProposalListItem.getProposal());
|
||||
else
|
||||
hideProposalDisplay();
|
||||
|
||||
onPhaseChanged(daoFacade.phaseProperty().get());
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Create views
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void createProposalsTableView() {
|
||||
createProposalsTableView(Res.get("dao.proposal.active.header"), -10);
|
||||
}
|
||||
|
||||
private void createProposalsTableView(String header, double top) {
|
||||
TableGroupHeadline proposalsHeadline = new TableGroupHeadline(header);
|
||||
GridPane.setRowIndex(proposalsHeadline, ++gridRow);
|
||||
GridPane.setMargin(proposalsHeadline, new Insets(top, -10, -10, -10));
|
||||
GridPane.setColumnSpan(proposalsHeadline, 2);
|
||||
root.getChildren().add(proposalsHeadline);
|
||||
|
||||
proposalTableView = new TableView<>();
|
||||
proposalTableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData")));
|
||||
proposalTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
proposalTableView.setPrefHeight(200);
|
||||
|
||||
createProposalColumns(proposalTableView);
|
||||
GridPane.setRowIndex(proposalTableView, gridRow);
|
||||
GridPane.setMargin(proposalTableView, new Insets(top + 20, -10, 5, -10));
|
||||
GridPane.setColumnSpan(proposalTableView, 2);
|
||||
GridPane.setHgrow(proposalTableView, Priority.ALWAYS);
|
||||
root.getChildren().add(proposalTableView);
|
||||
|
||||
proposalTableView.setItems(sortedList);
|
||||
}
|
||||
|
||||
private void createEmptyProposalDisplay() {
|
||||
proposalDisplay = new ProposalDisplay(detailsGridPane, bsqFormatter, bsqWalletService, daoFacade);
|
||||
proposalDisplayView = proposalDisplay.getView();
|
||||
GridPane.setMargin(proposalDisplayView, new Insets(10, -10, 0, -10));
|
||||
GridPane.setRowIndex(proposalDisplayView, ++gridRow);
|
||||
GridPane.setColumnSpan(proposalDisplayView, 2);
|
||||
root.getChildren().add(proposalDisplayView);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TableColumns
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void createProposalColumns(TableView<OpenProposalListItem> tableView) {
|
||||
TableColumn<OpenProposalListItem, OpenProposalListItem> dateColumn = new AutoTooltipTableColumn<OpenProposalListItem, OpenProposalListItem>(Res.get("shared.dateTime")) {
|
||||
{
|
||||
setMinWidth(190);
|
||||
setMaxWidth(190);
|
||||
}
|
||||
};
|
||||
dateColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
dateColumn.setCellFactory(
|
||||
new Callback<TableColumn<OpenProposalListItem, OpenProposalListItem>, TableCell<OpenProposalListItem,
|
||||
OpenProposalListItem>>() {
|
||||
@Override
|
||||
public TableCell<OpenProposalListItem, OpenProposalListItem> call(
|
||||
TableColumn<OpenProposalListItem, OpenProposalListItem> column) {
|
||||
return new TableCell<OpenProposalListItem, OpenProposalListItem>() {
|
||||
@Override
|
||||
public void updateItem(final OpenProposalListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null)
|
||||
setText(bsqFormatter.formatDateTime(item.getProposal().getCreationDate()));
|
||||
else
|
||||
setText("");
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
dateColumn.setComparator(Comparator.comparing(o3 -> o3.getProposal().getCreationDate()));
|
||||
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
||||
tableView.getColumns().add(dateColumn);
|
||||
tableView.getSortOrder().add(dateColumn);
|
||||
|
||||
TableColumn<OpenProposalListItem, OpenProposalListItem> nameColumn = new AutoTooltipTableColumn<>(Res.get("shared.name"));
|
||||
nameColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
nameColumn.setCellFactory(
|
||||
new Callback<TableColumn<OpenProposalListItem, OpenProposalListItem>, TableCell<OpenProposalListItem,
|
||||
OpenProposalListItem>>() {
|
||||
@Override
|
||||
public TableCell<OpenProposalListItem, OpenProposalListItem> call(
|
||||
TableColumn<OpenProposalListItem, OpenProposalListItem> column) {
|
||||
return new TableCell<OpenProposalListItem, OpenProposalListItem>() {
|
||||
@Override
|
||||
public void updateItem(final OpenProposalListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null)
|
||||
setText(item.getProposal().getName());
|
||||
else
|
||||
setText("");
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
nameColumn.setComparator(Comparator.comparing(o2 -> o2.getProposal().getName()));
|
||||
tableView.getColumns().add(nameColumn);
|
||||
|
||||
TableColumn<OpenProposalListItem, OpenProposalListItem> uidColumn = new AutoTooltipTableColumn<>(Res.get("shared.id"));
|
||||
uidColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
uidColumn.setCellFactory(
|
||||
new Callback<TableColumn<OpenProposalListItem, OpenProposalListItem>, TableCell<OpenProposalListItem,
|
||||
OpenProposalListItem>>() {
|
||||
|
||||
@Override
|
||||
public TableCell<OpenProposalListItem, OpenProposalListItem> call(TableColumn<OpenProposalListItem,
|
||||
OpenProposalListItem> column) {
|
||||
return new TableCell<OpenProposalListItem, OpenProposalListItem>() {
|
||||
private HyperlinkWithIcon field;
|
||||
|
||||
@Override
|
||||
public void updateItem(final OpenProposalListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty) {
|
||||
final Proposal proposal = item.getProposal();
|
||||
field = new HyperlinkWithIcon(proposal.getShortId());
|
||||
field.setOnAction(event -> {
|
||||
new ProposalWindow(bsqFormatter, bsqWalletService, proposal, daoFacade).show();
|
||||
});
|
||||
field.setTooltip(new Tooltip(Res.get("tooltip.openPopupForDetails")));
|
||||
setGraphic(field);
|
||||
} else {
|
||||
setGraphic(null);
|
||||
if (field != null)
|
||||
field.setOnAction(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
uidColumn.setComparator(Comparator.comparing(o -> o.getProposal().getUid()));
|
||||
tableView.getColumns().add(uidColumn);
|
||||
|
||||
|
||||
TableColumn<OpenProposalListItem, OpenProposalListItem> confidenceColumn = new TableColumn<>(Res.get("shared.confirmations"));
|
||||
confidenceColumn.setMinWidth(130);
|
||||
confidenceColumn.setMaxWidth(confidenceColumn.getMinWidth());
|
||||
|
||||
confidenceColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
|
||||
confidenceColumn.setCellFactory(new Callback<TableColumn<OpenProposalListItem, OpenProposalListItem>,
|
||||
TableCell<OpenProposalListItem, OpenProposalListItem>>() {
|
||||
|
||||
@Override
|
||||
public TableCell<OpenProposalListItem, OpenProposalListItem> call(TableColumn<OpenProposalListItem,
|
||||
OpenProposalListItem> column) {
|
||||
return new TableCell<OpenProposalListItem, OpenProposalListItem>() {
|
||||
|
||||
@Override
|
||||
public void updateItem(final OpenProposalListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null && !empty) {
|
||||
setGraphic(item.getTxConfidenceIndicator());
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
confidenceColumn.setComparator(Comparator.comparing(OpenProposalListItem::getConfirmations));
|
||||
tableView.getColumns().add(confidenceColumn);
|
||||
|
||||
TableColumn<OpenProposalListItem, OpenProposalListItem> actionColumn = new TableColumn<>();
|
||||
actionColumn.setMinWidth(130);
|
||||
actionColumn.setMaxWidth(actionColumn.getMinWidth());
|
||||
|
||||
actionColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
|
||||
actionColumn.setCellFactory(new Callback<TableColumn<OpenProposalListItem, OpenProposalListItem>,
|
||||
TableCell<OpenProposalListItem, OpenProposalListItem>>() {
|
||||
|
||||
@Override
|
||||
public TableCell<OpenProposalListItem, OpenProposalListItem> call(TableColumn<OpenProposalListItem,
|
||||
OpenProposalListItem> column) {
|
||||
return new TableCell<OpenProposalListItem, OpenProposalListItem>() {
|
||||
Button button;
|
||||
|
||||
@Override
|
||||
public void updateItem(final OpenProposalListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null && !empty) {
|
||||
OpenProposalListItem openProposalListItem = item;
|
||||
if (button == null) {
|
||||
button = openProposalListItem.getButton();
|
||||
button.setOnAction(e -> {
|
||||
OpenProposalsView.this.selectedBaseProposalListItem = item;
|
||||
OpenProposalsView.this.onButtonClick();
|
||||
});
|
||||
setGraphic(button);
|
||||
}
|
||||
openProposalListItem.onPhaseChanged(currentPhase);
|
||||
} else {
|
||||
setGraphic(null);
|
||||
if (button != null) {
|
||||
button.setOnAction(null);
|
||||
button = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
actionColumn.setComparator(Comparator.comparing(OpenProposalListItem::getConfirmations));
|
||||
tableView.getColumns().add(actionColumn);
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue