mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 15:10:44 +01:00
Add UI for myVotes
This commit is contained in:
parent
11049d1e5e
commit
a34bf50650
17 changed files with 1039 additions and 217 deletions
|
@ -37,6 +37,7 @@ import bisq.core.locale.Res;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
|
@ -56,12 +57,13 @@ import javafx.beans.value.ChangeListener;
|
|||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@FxmlView
|
||||
|
@ -69,12 +71,14 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
|
|||
|
||||
protected final ProposalCollectionsService proposalCollectionsService;
|
||||
protected final BsqBlockChain bsqBlockChain;
|
||||
protected final ObservableList<ProposalListItem> proposalListItems = FXCollections.observableArrayList();
|
||||
protected TableView<ProposalListItem> tableView;
|
||||
protected final BsqWalletService bsqWalletService;
|
||||
protected final BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher;
|
||||
protected final BsqFormatter bsqFormatter;
|
||||
protected SortedList<ProposalListItem> sortedList = new SortedList<>(proposalListItems);
|
||||
|
||||
protected final ObservableList<ProposalListItem> proposalListItems = FXCollections.observableArrayList();
|
||||
protected final SortedList<ProposalListItem> sortedList = new SortedList<>(proposalListItems);
|
||||
protected final List<Node> proposalViewItems = new ArrayList<>();
|
||||
protected TableView<ProposalListItem> proposalTableView;
|
||||
protected Subscription selectedProposalSubscription;
|
||||
protected ProposalDisplay proposalDisplay;
|
||||
protected int gridRow = 0;
|
||||
|
@ -85,6 +89,7 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
|
|||
protected final DaoPeriodService daoPeriodService;
|
||||
protected DaoPeriodService.Phase currentPhase;
|
||||
protected Subscription phaseSubscription;
|
||||
private ScrollPane proposalDisplayView;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -111,80 +116,41 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
|
|||
super.initialize();
|
||||
root.getStyleClass().add("vote-root");
|
||||
|
||||
proposalListChangeListener = c -> updateList();
|
||||
detailsGridPane = new GridPane();
|
||||
|
||||
proposalListChangeListener = c -> updateProposalList();
|
||||
phaseChangeListener = (observable, oldValue, newValue) -> onPhaseChanged(newValue);
|
||||
}
|
||||
|
||||
protected void createTableView() {
|
||||
TableGroupHeadline proposalsHeadline = new TableGroupHeadline(Res.get("dao.proposal.active.header"));
|
||||
GridPane.setRowIndex(proposalsHeadline, ++gridRow);
|
||||
GridPane.setMargin(proposalsHeadline, new Insets(-10, -10, -10, -10));
|
||||
GridPane.setColumnSpan(proposalsHeadline, 2);
|
||||
root.getChildren().add(proposalsHeadline);
|
||||
|
||||
tableView = new TableView<>();
|
||||
tableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData")));
|
||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
|
||||
createColumns(tableView);
|
||||
GridPane.setRowIndex(tableView, gridRow);
|
||||
GridPane.setMargin(tableView, new Insets(10, -10, 5, -10));
|
||||
GridPane.setColumnSpan(tableView, 2);
|
||||
GridPane.setHgrow(tableView, Priority.ALWAYS);
|
||||
root.getChildren().add(tableView);
|
||||
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
tableView.setItems(sortedList);
|
||||
}
|
||||
|
||||
protected void createProposalDisplay() {
|
||||
detailsGridPane = new GridPane();
|
||||
proposalDisplay = new ProposalDisplay(detailsGridPane, bsqFormatter, bsqWalletService, null);
|
||||
final ScrollPane proposalDisplayView = proposalDisplay.getView();
|
||||
GridPane.setMargin(proposalDisplayView, new Insets(10, -10, 0, -10));
|
||||
GridPane.setRowIndex(proposalDisplayView, ++gridRow);
|
||||
GridPane.setColumnSpan(proposalDisplayView, 2);
|
||||
root.getChildren().add(proposalDisplayView);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
phaseSubscription = EasyBind.subscribe(daoPeriodService.getPhaseProperty(), phase -> {
|
||||
if (!phase.equals(this.currentPhase)) {
|
||||
this.currentPhase = phase;
|
||||
onSelectProposal(selectedProposalListItem);
|
||||
}
|
||||
});
|
||||
phaseSubscription = EasyBind.subscribe(daoPeriodService.getPhaseProperty(), this::onPhaseChanged);
|
||||
selectedProposalSubscription = EasyBind.subscribe(proposalTableView.getSelectionModel().selectedItemProperty(), this::onSelectProposal);
|
||||
|
||||
daoPeriodService.getPhaseProperty().addListener(phaseChangeListener);
|
||||
onPhaseChanged(daoPeriodService.getPhaseProperty().get());
|
||||
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
|
||||
selectedProposalSubscription = EasyBind.subscribe(tableView.getSelectionModel().selectedItemProperty(), this::onSelectProposal);
|
||||
|
||||
bsqBlockChainChangeDispatcher.addBsqBlockChainListener(this);
|
||||
proposalCollectionsService.getAllProposals().addListener(proposalListChangeListener);
|
||||
updateList();
|
||||
|
||||
onPhaseChanged(daoPeriodService.getPhaseProperty().get());
|
||||
|
||||
sortedList.comparatorProperty().bind(proposalTableView.comparatorProperty());
|
||||
|
||||
updateProposalList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
phaseSubscription.unsubscribe();
|
||||
daoPeriodService.getPhaseProperty().removeListener(phaseChangeListener);
|
||||
|
||||
sortedList.comparatorProperty().unbind();
|
||||
|
||||
selectedProposalSubscription.unsubscribe();
|
||||
|
||||
daoPeriodService.getPhaseProperty().removeListener(phaseChangeListener);
|
||||
bsqBlockChainChangeDispatcher.removeBsqBlockChainListener(this);
|
||||
proposalCollectionsService.getAllProposals().removeListener(proposalListChangeListener);
|
||||
|
||||
proposalListItems.forEach(ProposalListItem::cleanup);
|
||||
sortedList.comparatorProperty().unbind();
|
||||
|
||||
tableView.getSelectionModel().clearSelection();
|
||||
removeProposalDisplay();
|
||||
proposalListItems.forEach(ProposalListItem::cleanup);
|
||||
proposalTableView.getSelectionModel().clearSelection();
|
||||
selectedProposalListItem = null;
|
||||
}
|
||||
|
||||
|
@ -199,16 +165,93 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
|
|||
//UserThread.execute(this::updateList);
|
||||
}
|
||||
|
||||
abstract protected void updateList();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Create views
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
protected void createProposalsTableView() {
|
||||
createProposalsTableView(Res.get("dao.proposal.active.header"), -10);
|
||||
}
|
||||
|
||||
protected 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);
|
||||
|
||||
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);
|
||||
|
||||
proposalViewItems.add(proposalsHeadline);
|
||||
proposalViewItems.add(proposalTableView);
|
||||
}
|
||||
|
||||
protected void createProposalDisplay() {
|
||||
proposalDisplay = new ProposalDisplay(detailsGridPane, bsqFormatter, bsqWalletService, null);
|
||||
proposalDisplayView = proposalDisplay.getView();
|
||||
GridPane.setMargin(proposalDisplayView, new Insets(10, -10, 0, -10));
|
||||
GridPane.setRowIndex(proposalDisplayView, ++gridRow);
|
||||
GridPane.setColumnSpan(proposalDisplayView, 2);
|
||||
root.getChildren().add(proposalDisplayView);
|
||||
}
|
||||
|
||||
protected void hideProposalDisplay() {
|
||||
proposalDisplay.removeAllFields();
|
||||
proposalDisplayView.setVisible(false);
|
||||
proposalDisplayView.setManaged(false);
|
||||
}
|
||||
|
||||
protected void showProposalDisplay(Proposal proposal) {
|
||||
proposalDisplayView.setVisible(true);
|
||||
proposalDisplayView.setManaged(true);
|
||||
|
||||
proposalDisplay.createAllFields(Res.get("dao.proposal.selectedProposal"), 0, 0, proposal.getType(),
|
||||
false, false);
|
||||
proposalDisplay.setEditable(false);
|
||||
proposalDisplay.applyProposalPayload(proposal.getProposalPayload());
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Handlers
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected void onSelectProposal(ProposalListItem item) {
|
||||
selectedProposalListItem = item;
|
||||
if (item != null)
|
||||
showProposalDisplay(item.getProposal());
|
||||
else
|
||||
hideProposalDisplay();
|
||||
}
|
||||
|
||||
protected void onPhaseChanged(DaoPeriodService.Phase phase) {
|
||||
if (!phase.equals(this.currentPhase)) {
|
||||
this.currentPhase = phase;
|
||||
onSelectProposal(selectedProposalListItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected void doUpdateList(FilteredList<Proposal> list) {
|
||||
abstract protected void updateProposalList();
|
||||
|
||||
protected void doUpdateProposalList(List<Proposal> list) {
|
||||
proposalListItems.forEach(ProposalListItem::cleanup);
|
||||
|
||||
proposalListItems.setAll(list.stream()
|
||||
|
@ -221,34 +264,23 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
|
|||
bsqFormatter))
|
||||
.collect(Collectors.toSet()));
|
||||
|
||||
if (list.isEmpty() && proposalDisplay != null)
|
||||
proposalDisplay.removeAllFields();
|
||||
if (list.isEmpty())
|
||||
hideProposalDisplay();
|
||||
}
|
||||
|
||||
protected void onSelectProposal(ProposalListItem item) {
|
||||
selectedProposalListItem = item;
|
||||
if (item != null) {
|
||||
final Proposal proposal = item.getProposal();
|
||||
|
||||
removeProposalDisplay();
|
||||
|
||||
//TODO
|
||||
proposalDisplay = new ProposalDisplay(detailsGridPane, bsqFormatter, bsqWalletService, null);
|
||||
proposalDisplay.createAllFields(Res.get("dao.proposal.selectedProposal"), 0, 0, proposal.getType(),
|
||||
false, false);
|
||||
proposalDisplay.setAllFieldsEditable(false);
|
||||
proposalDisplay.fillWithData(proposal.getProposalPayload());
|
||||
}
|
||||
protected void changeProposalViewItemsVisibility(boolean value) {
|
||||
proposalViewItems.forEach(node -> {
|
||||
node.setVisible(value);
|
||||
node.setManaged(value);
|
||||
});
|
||||
}
|
||||
|
||||
protected void removeProposalDisplay() {
|
||||
if (proposalDisplay != null) {
|
||||
proposalDisplay.removeAllFields();
|
||||
proposalDisplay = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void createColumns(TableView<ProposalListItem> tableView) {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TableColumns
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected void createProposalColumns(TableView<ProposalListItem> tableView) {
|
||||
TableColumn<ProposalListItem, ProposalListItem> dateColumn = new AutoTooltipTableColumn<ProposalListItem, ProposalListItem>(Res.get("shared.dateTime")) {
|
||||
{
|
||||
setMinWidth(190);
|
||||
|
@ -302,8 +334,31 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
|
|||
nameColumn.setComparator(Comparator.comparing(o2 -> o2.getProposal().getProposalPayload().getName()));
|
||||
tableView.getColumns().add(nameColumn);
|
||||
|
||||
TableColumn<ProposalListItem, ProposalListItem> uidColumn = new AutoTooltipTableColumn<>(Res.get("shared.id"));
|
||||
TableColumn<ProposalListItem, ProposalListItem> titleColumn = new AutoTooltipTableColumn<>(Res.get("dao.proposal.title"));
|
||||
titleColumn.setPrefWidth(100);
|
||||
titleColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
titleColumn.setCellFactory(
|
||||
new Callback<TableColumn<ProposalListItem, ProposalListItem>, TableCell<ProposalListItem,
|
||||
ProposalListItem>>() {
|
||||
@Override
|
||||
public TableCell<ProposalListItem, ProposalListItem> call(
|
||||
TableColumn<ProposalListItem, ProposalListItem> column) {
|
||||
return new TableCell<ProposalListItem, ProposalListItem>() {
|
||||
@Override
|
||||
public void updateItem(final ProposalListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null)
|
||||
setText(item.getProposal().getProposalPayload().getTitle());
|
||||
else
|
||||
setText("");
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
titleColumn.setComparator(Comparator.comparing(o2 -> o2.getProposal().getProposalPayload().getTitle()));
|
||||
tableView.getColumns().add(titleColumn);
|
||||
|
||||
TableColumn<ProposalListItem, ProposalListItem> uidColumn = new AutoTooltipTableColumn<>(Res.get("shared.id"));
|
||||
uidColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
uidColumn.setCellFactory(
|
||||
new Callback<TableColumn<ProposalListItem, ProposalListItem>, TableCell<ProposalListItem,
|
||||
|
@ -338,7 +393,9 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> i
|
|||
});
|
||||
uidColumn.setComparator(Comparator.comparing(o -> o.getProposal().getProposalPayload().getUid()));
|
||||
tableView.getColumns().add(uidColumn);
|
||||
}
|
||||
|
||||
protected void createConfidenceColumn(TableView<ProposalListItem> tableView) {
|
||||
TableColumn<ProposalListItem, ProposalListItem> confidenceColumn = new TableColumn<>(Res.get("shared.confirmations"));
|
||||
confidenceColumn.setMinWidth(130);
|
||||
confidenceColumn.setMaxWidth(confidenceColumn.getMinWidth());
|
||||
|
|
|
@ -60,8 +60,8 @@ public class ProposalDetailsWindow extends Overlay<ProposalDetailsWindow> {
|
|||
proposalDisplay.createAllFields(Res.get("dao.proposal.details"), 1, Layout.GROUP_DISTANCE,
|
||||
proposalPayload.getType(), false, true);
|
||||
|
||||
proposalDisplay.setAllFieldsEditable(false);
|
||||
proposalDisplay.fillWithData(proposalPayload);
|
||||
proposalDisplay.setEditable(false);
|
||||
proposalDisplay.applyProposalPayload(proposalPayload);
|
||||
|
||||
closeButton = addButtonAfterGroup(gridPane, proposalDisplay.incrementAndGetGridRow(), Res.get("shared.close"));
|
||||
closeButton.setOnAction(e -> doClose());
|
||||
|
|
|
@ -92,6 +92,7 @@ public class ProposalDisplay {
|
|||
|
||||
public void createAllFields(String title, int gridRowStartIndex, double top, ProposalType proposalType,
|
||||
boolean isMakeProposalScreen, boolean showDetails) {
|
||||
removeAllFields();
|
||||
this.gridRowStartIndex = gridRowStartIndex;
|
||||
this.gridRow = gridRowStartIndex;
|
||||
int rowSpan;
|
||||
|
@ -114,7 +115,7 @@ public class ProposalDisplay {
|
|||
top == Layout.GROUP_DISTANCE ? Layout.FIRST_ROW_AND_GROUP_DISTANCE : Layout.FIRST_ROW_DISTANCE).second;
|
||||
}
|
||||
|
||||
titleTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.proposal.display.title")).second;
|
||||
titleTextField = addLabelInputTextField(gridPane, ++gridRow, Res.getWithCol("dao.proposal.title")).second;
|
||||
|
||||
descriptionTextArea = addLabelTextArea(gridPane, ++gridRow, Res.get("dao.proposal.display.description"), Res.get("dao.proposal.display.description.prompt", maxLengthDescriptionText)).second;
|
||||
descriptionTextArea.setMaxHeight(42); // for 2 lines
|
||||
|
@ -152,7 +153,7 @@ public class ProposalDisplay {
|
|||
Res.get("dao.proposal.display.txId"), "").second;
|
||||
}
|
||||
|
||||
public void fillWithData(ProposalPayload proposalPayload) {
|
||||
public void applyProposalPayload(ProposalPayload proposalPayload) {
|
||||
if (uidTextField != null)
|
||||
uidTextField.setText(proposalPayload.getUid());
|
||||
nameTextField.setText(proposalPayload.getName());
|
||||
|
@ -204,7 +205,7 @@ public class ProposalDisplay {
|
|||
bsqAddressTextField.setText("B" + bsqWalletService.getUnusedAddress().toBase58());
|
||||
}
|
||||
|
||||
public void setAllFieldsEditable(boolean isEditable) {
|
||||
public void setEditable(boolean isEditable) {
|
||||
nameTextField.setEditable(isEditable);
|
||||
titleTextField.setEditable(isEditable);
|
||||
descriptionTextArea.setEditable(isEditable);
|
||||
|
@ -224,9 +225,7 @@ public class ProposalDisplay {
|
|||
public void removeAllFields() {
|
||||
if (gridRow > 0) {
|
||||
clearForm();
|
||||
|
||||
GUIUtil.removeChildrenFromGridPaneRows(gridPane, gridRowStartIndex, gridRow + 1);
|
||||
|
||||
gridRow = gridRowStartIndex;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,10 +123,9 @@ public class ProposalListItem implements BsqBlockChainListener {
|
|||
|
||||
daoPeriodService.getPhaseProperty().addListener(phaseChangeListener);
|
||||
proposal.getVoteResultProperty().addListener(voteResultChangeListener);
|
||||
applyState(daoPeriodService.getPhaseProperty().get(), proposal.getVoteResult());
|
||||
}
|
||||
|
||||
private void applyState(DaoPeriodService.Phase newValue, VoteResult voteResult) {
|
||||
public void applyState(DaoPeriodService.Phase newValue, VoteResult voteResult) {
|
||||
actionButton.setText("");
|
||||
actionButton.setVisible(false);
|
||||
actionButton.setOnAction(null);
|
||||
|
@ -141,7 +140,10 @@ public class ProposalListItem implements BsqBlockChainListener {
|
|||
actionButton.setText(Res.get("shared.remove"));
|
||||
actionButton.setGraphic(actionButtonIconView);
|
||||
actionButtonIconView.setId("image-remove");
|
||||
actionButton.setOnAction(e -> onRemoveHandler.run());
|
||||
actionButton.setOnAction(e -> {
|
||||
if (onRemoveHandler != null)
|
||||
onRemoveHandler.run();
|
||||
});
|
||||
actionNode = actionButton;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -30,6 +30,8 @@ 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.myvotes.MyVotesView;
|
||||
import bisq.desktop.main.dao.proposal.votes.VotesView;
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
|
||||
|
@ -49,7 +51,7 @@ public class ProposalView extends ActivatableViewAndModel {
|
|||
private final ViewLoader viewLoader;
|
||||
private final Navigation navigation;
|
||||
|
||||
private MenuItem dashboard, create, proposed, past;
|
||||
private MenuItem dashboard, make, active, myVotes, votes, closed;
|
||||
private Navigation.Listener listener;
|
||||
|
||||
@FXML
|
||||
|
@ -77,18 +79,24 @@ public class ProposalView extends ActivatableViewAndModel {
|
|||
|
||||
ToggleGroup toggleGroup = new ToggleGroup();
|
||||
dashboard = new MenuItem(navigation, toggleGroup, Res.get("shared.dashboard"), ProposalDashboardView.class, AwesomeIcon.DASHBOARD);
|
||||
create = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.make"), MakeProposalView.class, AwesomeIcon.EDIT);
|
||||
proposed = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.active"), ActiveProposalsView.class, AwesomeIcon.STACKEXCHANGE);
|
||||
past = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.closed"), ClosedProposalsView.class, AwesomeIcon.LIST);
|
||||
leftVBox.getChildren().addAll(dashboard, create, proposed, past);
|
||||
make = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.make"), MakeProposalView.class, AwesomeIcon.EDIT);
|
||||
active = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.active"), ActiveProposalsView.class, AwesomeIcon.STACKEXCHANGE);
|
||||
myVotes = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.myVotes"), MyVotesView.class,
|
||||
AwesomeIcon.LIST);
|
||||
votes = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.votes"), VotesView.class, AwesomeIcon
|
||||
.LIST);
|
||||
closed = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.closed"), ClosedProposalsView.class, AwesomeIcon.LIST);
|
||||
leftVBox.getChildren().addAll(dashboard, make, active, myVotes, votes, closed);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
dashboard.activate();
|
||||
create.activate();
|
||||
proposed.activate();
|
||||
past.activate();
|
||||
make.activate();
|
||||
active.activate();
|
||||
myVotes.activate();
|
||||
votes.activate();
|
||||
closed.activate();
|
||||
|
||||
navigation.addListener(listener);
|
||||
ViewPath viewPath = navigation.getCurrentPath();
|
||||
|
@ -110,9 +118,11 @@ public class ProposalView extends ActivatableViewAndModel {
|
|||
navigation.removeListener(listener);
|
||||
|
||||
dashboard.deactivate();
|
||||
create.deactivate();
|
||||
proposed.deactivate();
|
||||
past.deactivate();
|
||||
make.deactivate();
|
||||
active.deactivate();
|
||||
myVotes.deactivate();
|
||||
votes.deactivate();
|
||||
closed.deactivate();
|
||||
}
|
||||
|
||||
private void loadView(Class<? extends View> viewClass) {
|
||||
|
@ -120,9 +130,11 @@ public class ProposalView extends ActivatableViewAndModel {
|
|||
content.getChildren().setAll(view.getRoot());
|
||||
|
||||
if (view instanceof ProposalDashboardView) dashboard.setSelected(true);
|
||||
else if (view instanceof MakeProposalView) create.setSelected(true);
|
||||
else if (view instanceof ActiveProposalsView) proposed.setSelected(true);
|
||||
else if (view instanceof ClosedProposalsView) past.setSelected(true);
|
||||
else if (view instanceof MakeProposalView) make.setSelected(true);
|
||||
else if (view instanceof ActiveProposalsView) active.setSelected(true);
|
||||
else if (view instanceof MyVotesView) myVotes.setSelected(true);
|
||||
else if (view instanceof VotesView) votes.setSelected(true);
|
||||
else if (view instanceof ClosedProposalsView) closed.setSelected(true);
|
||||
}
|
||||
|
||||
public Class<? extends View> getSelectedViewClass() {
|
||||
|
|
|
@ -19,6 +19,7 @@ package bisq.desktop.main.dao.proposal.active;
|
|||
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.components.TitledGroupBg;
|
||||
import bisq.desktop.main.dao.proposal.BaseProposalView;
|
||||
import bisq.desktop.main.dao.proposal.ProposalListItem;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
|
@ -41,6 +42,7 @@ import bisq.core.dao.vote.VoteService;
|
|||
import bisq.core.locale.Res;
|
||||
|
||||
import bisq.common.crypto.CryptoException;
|
||||
import bisq.common.util.Tuple2;
|
||||
import bisq.common.util.Tuple3;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
@ -53,6 +55,7 @@ import com.google.common.util.concurrent.FutureCallback;
|
|||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
|
@ -61,7 +64,9 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
|
|||
|
||||
import javafx.util.Callback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
@ -71,13 +76,14 @@ import static bisq.desktop.util.FormBuilder.addLabelInputTextField;
|
|||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
||||
|
||||
@FxmlView
|
||||
public class ActiveProposalsView extends BaseProposalView {
|
||||
public class ActiveProposalsView extends BaseProposalView implements BsqBalanceListener {
|
||||
|
||||
private final VoteService voteService;
|
||||
|
||||
private Button removeButton, acceptButton, rejectButton, cancelVoteButton, voteButton;
|
||||
private InputTextField stakeInputTextField;
|
||||
private BsqBalanceListener bsqBalanceListener;
|
||||
private List<Node> voteViewItems = new ArrayList<>();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
|
@ -100,70 +106,100 @@ public class ActiveProposalsView extends BaseProposalView {
|
|||
public void initialize() {
|
||||
super.initialize();
|
||||
|
||||
createTableView();
|
||||
|
||||
addTitledGroupBg(root, ++gridRow, 1, Res.get("dao.proposal.vote.header"), Layout.GROUP_DISTANCE - 20);
|
||||
stakeInputTextField = addLabelInputTextField(root, gridRow, Res.getWithCol("dao.proposal.vote.stake"), Layout
|
||||
.FIRST_ROW_AND_GROUP_DISTANCE - 20).second;
|
||||
voteButton = addButtonAfterGroup(root, ++gridRow, Res.get("dao.proposal.vote.button"));
|
||||
|
||||
createProposalsTableView();
|
||||
createVoteView();
|
||||
createProposalDisplay();
|
||||
|
||||
bsqBalanceListener = (availableBalance, unverifiedBalance) -> stakeInputTextField.setPromptText(Res.get("dao.proposal.vote.stake.prompt", bsqFormatter.formatCoinWithCode(availableBalance)));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
super.activate();
|
||||
|
||||
bsqWalletService.addBsqBalanceListener(bsqBalanceListener);
|
||||
stakeInputTextField.setPromptText(Res.get("dao.proposal.vote.stake.prompt", bsqFormatter.formatCoinWithCode
|
||||
(bsqWalletService.getAvailableBalance())));
|
||||
bsqWalletService.addBsqBalanceListener(this);
|
||||
|
||||
voteButton.setOnAction(e -> {
|
||||
Coin stake = bsqFormatter.parseToCoin(stakeInputTextField.getText());
|
||||
// TODO verify stake
|
||||
//TODO show popup
|
||||
try {
|
||||
voteService.publishBlindVote(stake, new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Transaction result) {
|
||||
//TODO
|
||||
}
|
||||
onUpdateBalances(bsqWalletService.getAvailableBalance(),
|
||||
bsqWalletService.getPendingBalance(),
|
||||
bsqWalletService.getLockedForVotingBalance(),
|
||||
bsqWalletService.getLockedInBondsBalance());
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
//TODO
|
||||
}
|
||||
});
|
||||
} catch (CryptoException e1) {
|
||||
//TODO show error popup
|
||||
e1.printStackTrace();
|
||||
} catch (InsufficientBsqException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (WalletException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (TransactionVerificationException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (InsufficientMoneyException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (ChangeBelowDustException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
});
|
||||
if (voteButton != null) {
|
||||
voteButton.setOnAction(e -> {
|
||||
Coin stake = bsqFormatter.parseToCoin(stakeInputTextField.getText());
|
||||
// TODO verify stake
|
||||
//TODO show popup
|
||||
try {
|
||||
voteService.publishBlindVote(stake, new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Transaction result) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
//TODO
|
||||
}
|
||||
});
|
||||
} catch (CryptoException e1) {
|
||||
//TODO show error popup
|
||||
e1.printStackTrace();
|
||||
} catch (InsufficientBsqException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (WalletException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (TransactionVerificationException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (InsufficientMoneyException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (ChangeBelowDustException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
super.deactivate();
|
||||
|
||||
bsqWalletService.removeBsqBalanceListener(bsqBalanceListener);
|
||||
voteButton.setOnAction(null);
|
||||
bsqWalletService.removeBsqBalanceListener(this);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Create views
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
private void createVoteView() {
|
||||
TitledGroupBg titledGroupBg = addTitledGroupBg(root, ++gridRow, 1, Res.get("dao.proposal.vote.header"),
|
||||
Layout.GROUP_DISTANCE - 20);
|
||||
final Tuple2<Label, InputTextField> tuple2 = addLabelInputTextField(root, gridRow,
|
||||
Res.getWithCol("dao.proposal.vote.stake"), Layout
|
||||
.FIRST_ROW_AND_GROUP_DISTANCE - 20);
|
||||
stakeInputTextField = tuple2.second;
|
||||
voteButton = addButtonAfterGroup(root, ++gridRow, Res.get("dao.proposal.vote.button"));
|
||||
|
||||
voteViewItems.add(titledGroupBg);
|
||||
voteViewItems.add(tuple2.first);
|
||||
voteViewItems.add(stakeInputTextField);
|
||||
voteViewItems.add(voteButton);
|
||||
|
||||
changeVoteViewItemsVisibility(false);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Handlers
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
protected void updateList() {
|
||||
doUpdateList(proposalCollectionsService.getActiveProposals());
|
||||
public void onUpdateBalances(Coin confirmedBalance,
|
||||
Coin pendingBalance,
|
||||
Coin lockedForVotingBalance,
|
||||
Coin lockedInBondsBalance) {
|
||||
stakeInputTextField.setPromptText(Res.get("dao.proposal.vote.stake.prompt",
|
||||
bsqFormatter.formatCoinWithCode(confirmedBalance)));
|
||||
}
|
||||
|
||||
protected void onSelectProposal(ProposalListItem item) {
|
||||
|
@ -209,23 +245,12 @@ public class ActiveProposalsView extends BaseProposalView {
|
|||
updateStateAfterVote();
|
||||
}
|
||||
|
||||
private void updateStateAfterVote() {
|
||||
removeProposalDisplay();
|
||||
proposalCollectionsService.persist();
|
||||
tableView.getSelectionModel().clearSelection();
|
||||
}
|
||||
|
||||
private void onRemove() {
|
||||
if (proposalCollectionsService.removeProposal(selectedProposalListItem.getProposal()))
|
||||
removeProposalDisplay();
|
||||
else
|
||||
new Popup<>().warning(Res.get("dao.proposal.active.remove.failed")).show();
|
||||
|
||||
tableView.getSelectionModel().clearSelection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPhaseChanged(DaoPeriodService.Phase phase) {
|
||||
super.onPhaseChanged(phase);
|
||||
|
||||
changeVoteViewItemsVisibility(phase == DaoPeriodService.Phase.OPEN_FOR_VOTING);
|
||||
|
||||
if (removeButton != null) {
|
||||
removeButton.setManaged(false);
|
||||
removeButton.setVisible(false);
|
||||
|
@ -286,9 +311,46 @@ public class ActiveProposalsView extends BaseProposalView {
|
|||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
protected void createColumns(TableView<ProposalListItem> tableView) {
|
||||
super.createColumns(tableView);
|
||||
protected void updateProposalList() {
|
||||
doUpdateProposalList(proposalCollectionsService.getActiveProposals());
|
||||
}
|
||||
|
||||
private void updateStateAfterVote() {
|
||||
hideProposalDisplay();
|
||||
proposalCollectionsService.persist();
|
||||
proposalTableView.getSelectionModel().clearSelection();
|
||||
}
|
||||
|
||||
private void changeVoteViewItemsVisibility(boolean value) {
|
||||
voteViewItems.forEach(node -> {
|
||||
node.setVisible(value);
|
||||
node.setManaged(value);
|
||||
});
|
||||
}
|
||||
|
||||
private void onRemove() {
|
||||
if (proposalCollectionsService.removeProposal(selectedProposalListItem.getProposal()))
|
||||
hideProposalDisplay();
|
||||
else
|
||||
new Popup<>().warning(Res.get("dao.proposal.active.remove.failed")).show();
|
||||
|
||||
proposalTableView.getSelectionModel().clearSelection();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TableColumns
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
protected void createProposalColumns(TableView<ProposalListItem> tableView) {
|
||||
super.createProposalColumns(tableView);
|
||||
createConfidenceColumn(tableView);
|
||||
|
||||
TableColumn<ProposalListItem, ProposalListItem> actionColumn = new TableColumn<>();
|
||||
actionColumn.setMinWidth(130);
|
||||
|
@ -313,7 +375,11 @@ public class ActiveProposalsView extends BaseProposalView {
|
|||
if (node == null) {
|
||||
node = item.getActionNode();
|
||||
setGraphic(node);
|
||||
item.setOnRemoveHandler(ActiveProposalsView.this::onRemove);
|
||||
item.setOnRemoveHandler(() -> {
|
||||
ActiveProposalsView.this.selectedProposalListItem = item;
|
||||
ActiveProposalsView.this.onRemove();
|
||||
});
|
||||
item.applyState(currentPhase, item.getProposal().getVoteResultProperty().get());
|
||||
}
|
||||
} else {
|
||||
setGraphic(null);
|
||||
|
|
|
@ -51,8 +51,7 @@ public class ClosedProposalsView extends BaseProposalView {
|
|||
public void initialize() {
|
||||
super.initialize();
|
||||
|
||||
createTableView();
|
||||
|
||||
createProposalsTableView();
|
||||
createProposalDisplay();
|
||||
}
|
||||
|
||||
|
@ -67,8 +66,8 @@ public class ClosedProposalsView extends BaseProposalView {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void updateList() {
|
||||
doUpdateList(proposalCollectionsService.getClosedProposals());
|
||||
protected void updateProposalList() {
|
||||
doUpdateProposalList(proposalCollectionsService.getClosedProposals());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.myvotes.MyVotesView"
|
||||
hgap="5.0" vgap="5.0"
|
||||
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
|
||||
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="-10.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,377 @@
|
|||
/*
|
||||
* 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.myvotes;
|
||||
|
||||
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.dao.proposal.BaseProposalView;
|
||||
import bisq.desktop.main.dao.proposal.ProposalListItem;
|
||||
import bisq.desktop.util.BsqFormatter;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
import bisq.desktop.util.Layout;
|
||||
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.dao.DaoPeriodService;
|
||||
import bisq.core.dao.blockchain.BsqBlockChain;
|
||||
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
|
||||
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
|
||||
import bisq.core.dao.proposal.ProposalCollectionsService;
|
||||
import bisq.core.dao.proposal.ProposalList;
|
||||
import bisq.core.dao.vote.BooleanVoteResult;
|
||||
import bisq.core.dao.vote.VoteResult;
|
||||
import bisq.core.dao.vote.VoteService;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.user.Preferences;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.image.ImageView;
|
||||
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.ObservableList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@FxmlView
|
||||
public class MyVotesView extends BaseProposalView {
|
||||
|
||||
private final VoteService voteService;
|
||||
private final ReadableBsqBlockChain readableBsqBlockChain;
|
||||
private final Preferences preferences;
|
||||
|
||||
private final ObservableList<VoteListItem> voteListItems = FXCollections.observableArrayList();
|
||||
private SortedList<VoteListItem> sortedList = new SortedList<>(voteListItems);
|
||||
private TableView<VoteListItem> votesTableView;
|
||||
private VoteListItem selectedVoteListItem;
|
||||
private Subscription selectedVoteSubscription;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private MyVotesView(ProposalCollectionsService voteRequestManger,
|
||||
DaoPeriodService daoPeriodService,
|
||||
VoteService voteService,
|
||||
BsqWalletService bsqWalletService,
|
||||
BsqBlockChain bsqBlockChain,
|
||||
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
|
||||
ReadableBsqBlockChain readableBsqBlockChain,
|
||||
Preferences preferences,
|
||||
BsqFormatter bsqFormatter) {
|
||||
super(voteRequestManger, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, daoPeriodService,
|
||||
bsqFormatter);
|
||||
this.voteService = voteService;
|
||||
this.readableBsqBlockChain = readableBsqBlockChain;
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
|
||||
createVoteTableView();
|
||||
createProposalsTableView(Res.get("dao.proposal.myVotes.proposals.header"), Layout.GROUP_DISTANCE - 20);
|
||||
createProposalDisplay();
|
||||
|
||||
changeProposalViewItemsVisibility(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
super.activate();
|
||||
|
||||
selectedVoteSubscription = EasyBind.subscribe(votesTableView.getSelectionModel().selectedItemProperty(),
|
||||
this::onSelectVote);
|
||||
|
||||
sortedList.comparatorProperty().bind(votesTableView.comparatorProperty());
|
||||
|
||||
voteListItems.clear();
|
||||
List<VoteListItem> items = voteService.getVoteList().stream()
|
||||
.map(vote -> new VoteListItem(vote, bsqWalletService, readableBsqBlockChain))
|
||||
.collect(Collectors.toList());
|
||||
voteListItems.addAll(items);
|
||||
}
|
||||
|
||||
private void onSelectVote(VoteListItem voteListItem) {
|
||||
selectedVoteListItem = voteListItem;
|
||||
changeProposalViewItemsVisibility(selectedVoteListItem != null);
|
||||
updateProposalList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
super.deactivate();
|
||||
|
||||
selectedVoteSubscription.unsubscribe();
|
||||
|
||||
changeProposalViewItemsVisibility(false);
|
||||
votesTableView.getSelectionModel().clearSelection();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Create views
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void createVoteTableView() {
|
||||
TableGroupHeadline proposalsHeadline = new TableGroupHeadline(Res.get("dao.proposal.myVotes.header"));
|
||||
GridPane.setRowIndex(proposalsHeadline, ++gridRow);
|
||||
GridPane.setMargin(proposalsHeadline, new Insets(-10, -10, -10, -10));
|
||||
GridPane.setColumnSpan(proposalsHeadline, 2);
|
||||
root.getChildren().add(proposalsHeadline);
|
||||
|
||||
votesTableView = new TableView<>();
|
||||
votesTableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData")));
|
||||
votesTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
|
||||
createVoteColumns(votesTableView);
|
||||
GridPane.setRowIndex(votesTableView, gridRow);
|
||||
GridPane.setMargin(votesTableView, new Insets(10, -10, 5, -10));
|
||||
GridPane.setColumnSpan(votesTableView, 2);
|
||||
GridPane.setHgrow(votesTableView, Priority.ALWAYS);
|
||||
root.getChildren().add(votesTableView);
|
||||
|
||||
votesTableView.setItems(sortedList);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Handler
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void onShowProposalList(ProposalList proposalList) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
protected void updateProposalList() {
|
||||
if (selectedVoteListItem != null)
|
||||
doUpdateProposalList(selectedVoteListItem.getVote().getProposalList().getList());
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TableColumns
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void createVoteColumns(TableView<VoteListItem> tableView) {
|
||||
TableColumn<VoteListItem, VoteListItem> dateColumn = new AutoTooltipTableColumn<VoteListItem, VoteListItem>(Res.get("shared.dateTime")) {
|
||||
{
|
||||
setMinWidth(190);
|
||||
setMaxWidth(190);
|
||||
}
|
||||
};
|
||||
dateColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
dateColumn.setCellFactory(
|
||||
new Callback<TableColumn<VoteListItem, VoteListItem>, TableCell<VoteListItem,
|
||||
VoteListItem>>() {
|
||||
@Override
|
||||
public TableCell<VoteListItem, VoteListItem> call(
|
||||
TableColumn<VoteListItem, VoteListItem> column) {
|
||||
return new TableCell<VoteListItem, VoteListItem>() {
|
||||
@Override
|
||||
public void updateItem(final VoteListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null)
|
||||
setText(bsqFormatter.formatDateTime(new Date(item.getVote()
|
||||
.getDate())));
|
||||
else
|
||||
setText("");
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
dateColumn.setComparator(Comparator.comparing(o3 -> o3.getVote().getDate()));
|
||||
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
||||
tableView.getColumns().add(dateColumn);
|
||||
tableView.getSortOrder().add(dateColumn);
|
||||
|
||||
|
||||
TableColumn<VoteListItem, VoteListItem> proposalListColumn = new AutoTooltipTableColumn<>(Res.get("dao.proposal.myVotes.proposalList"));
|
||||
proposalListColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
proposalListColumn.setCellFactory(
|
||||
new Callback<TableColumn<VoteListItem, VoteListItem>, TableCell<VoteListItem,
|
||||
VoteListItem>>() {
|
||||
@Override
|
||||
public TableCell<VoteListItem, VoteListItem> call(
|
||||
TableColumn<VoteListItem, VoteListItem> column) {
|
||||
return new TableCell<VoteListItem, VoteListItem>() {
|
||||
@Override
|
||||
public void updateItem(final VoteListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null && !empty) {
|
||||
ProposalList proposalList = item.getVote().getProposalList();
|
||||
HyperlinkWithIcon field = new HyperlinkWithIcon(Res.get("dao.proposal.myVotes.showProposalList"), AwesomeIcon.INFO_SIGN);
|
||||
field.setOnAction(event -> onShowProposalList(proposalList));
|
||||
field.setTooltip(new Tooltip(Res.get("dao.proposal.myVotes.tooltip.showProposalList")));
|
||||
setGraphic(field);
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
proposalListColumn.setSortable(false);
|
||||
tableView.getColumns().add(proposalListColumn);
|
||||
|
||||
|
||||
TableColumn<VoteListItem, VoteListItem> txColumn = new AutoTooltipTableColumn<>(Res.get("dao.proposal.myVotes.tx"));
|
||||
txColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
txColumn.setCellFactory(
|
||||
new Callback<TableColumn<VoteListItem, VoteListItem>, TableCell<VoteListItem,
|
||||
VoteListItem>>() {
|
||||
@Override
|
||||
public TableCell<VoteListItem, VoteListItem> call(
|
||||
TableColumn<VoteListItem, VoteListItem> column) {
|
||||
return new TableCell<VoteListItem, VoteListItem>() {
|
||||
@Override
|
||||
public void updateItem(final VoteListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null && !empty) {
|
||||
String txId = item.getVote().getBlindVote().getTxId();
|
||||
HyperlinkWithIcon hyperlinkWithIcon = new HyperlinkWithIcon(txId, AwesomeIcon.EXTERNAL_LINK);
|
||||
hyperlinkWithIcon.setOnAction(event -> {
|
||||
if (txId != null)
|
||||
GUIUtil.openWebPage(preferences.getBlockChainExplorer().txUrl + txId);
|
||||
});
|
||||
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", txId)));
|
||||
setGraphic(hyperlinkWithIcon);
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
txColumn.setComparator(Comparator.comparing(o2 -> o2.getVote().getBlindVote().getTxId()));
|
||||
tableView.getColumns().add(txColumn);
|
||||
|
||||
TableColumn<VoteListItem, VoteListItem> 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<VoteListItem, VoteListItem>,
|
||||
TableCell<VoteListItem, VoteListItem>>() {
|
||||
|
||||
@Override
|
||||
public TableCell<VoteListItem, VoteListItem> call(TableColumn<VoteListItem,
|
||||
VoteListItem> column) {
|
||||
return new TableCell<VoteListItem, VoteListItem>() {
|
||||
|
||||
@Override
|
||||
public void updateItem(final VoteListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null && !empty) {
|
||||
setGraphic(item.getTxConfidenceIndicator());
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
confidenceColumn.setComparator(Comparator.comparing(VoteListItem::getConfirmations));
|
||||
tableView.getColumns().add(confidenceColumn);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void createProposalColumns(TableView<ProposalListItem> tableView) {
|
||||
super.createProposalColumns(tableView);
|
||||
|
||||
TableColumn<ProposalListItem, ProposalListItem> actionColumn = new TableColumn<>(Res.get("dao.proposal.myVotes.vote"));
|
||||
actionColumn.setMinWidth(50);
|
||||
actionColumn.setMaxWidth(actionColumn.getMinWidth());
|
||||
|
||||
actionColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
|
||||
actionColumn.setCellFactory(new Callback<TableColumn<ProposalListItem, ProposalListItem>,
|
||||
TableCell<ProposalListItem, ProposalListItem>>() {
|
||||
|
||||
@Override
|
||||
public TableCell<ProposalListItem, ProposalListItem> call(TableColumn<ProposalListItem,
|
||||
ProposalListItem> column) {
|
||||
return new TableCell<ProposalListItem, ProposalListItem>() {
|
||||
ImageView actionButtonIconView;
|
||||
|
||||
@Override
|
||||
public void updateItem(final ProposalListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null && !empty) {
|
||||
actionButtonIconView = new ImageView();
|
||||
VoteResult voteResult = item.getProposal().getVoteResult();
|
||||
if (voteResult instanceof BooleanVoteResult) {
|
||||
if (((BooleanVoteResult) voteResult).isAccepted()) {
|
||||
actionButtonIconView.setId("accepted");
|
||||
} else {
|
||||
actionButtonIconView.setId("rejected");
|
||||
}
|
||||
} else {
|
||||
//TODO
|
||||
}
|
||||
|
||||
setGraphic(actionButtonIconView);
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
actionColumn.setComparator(Comparator.comparing(ProposalListItem::getConfirmations));
|
||||
tableView.getColumns().add(actionColumn);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* 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.myvotes;
|
||||
|
||||
import bisq.desktop.components.indicator.TxConfidenceIndicator;
|
||||
|
||||
import bisq.core.btc.listeners.TxConfidenceListener;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.dao.blockchain.BsqBlockChainListener;
|
||||
import bisq.core.dao.blockchain.ReadableBsqBlockChain;
|
||||
import bisq.core.dao.blockchain.vo.Tx;
|
||||
import bisq.core.dao.vote.Vote;
|
||||
import bisq.core.locale.Res;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.TransactionConfidence;
|
||||
|
||||
import javafx.scene.control.Tooltip;
|
||||
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@ToString
|
||||
@Slf4j
|
||||
@EqualsAndHashCode
|
||||
public class VoteListItem implements BsqBlockChainListener {
|
||||
@Getter
|
||||
private final Vote vote;
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final ReadableBsqBlockChain readableBsqBlockChain;
|
||||
private final ChangeListener<Number> chainHeightListener;
|
||||
@Getter
|
||||
private TxConfidenceIndicator txConfidenceIndicator;
|
||||
@Getter
|
||||
private Integer confirmations = 0;
|
||||
|
||||
private TxConfidenceListener txConfidenceListener;
|
||||
private Tooltip tooltip = new Tooltip(Res.get("confidence.unknown"));
|
||||
private Transaction walletTransaction;
|
||||
@Setter
|
||||
private Runnable onRemoveHandler;
|
||||
|
||||
VoteListItem(Vote vote, BsqWalletService bsqWalletService, ReadableBsqBlockChain readableBsqBlockChain) {
|
||||
this.vote = vote;
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.readableBsqBlockChain = readableBsqBlockChain;
|
||||
|
||||
txConfidenceIndicator = new TxConfidenceIndicator();
|
||||
txConfidenceIndicator.setId("funds-confidence");
|
||||
|
||||
txConfidenceIndicator.setProgress(-1);
|
||||
txConfidenceIndicator.setPrefSize(24, 24);
|
||||
txConfidenceIndicator.setTooltip(tooltip);
|
||||
|
||||
|
||||
chainHeightListener = (observable, oldValue, newValue) -> setupConfidence();
|
||||
bsqWalletService.getChainHeightProperty().addListener(chainHeightListener);
|
||||
setupConfidence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBsqBlockChainChanged() {
|
||||
setupConfidence();
|
||||
}
|
||||
|
||||
private void setupConfidence() {
|
||||
final Tx tx = readableBsqBlockChain.getTxMap().get(vote.getBlindVote().getTxId());
|
||||
if (tx != null) {
|
||||
final String txId = tx.getId();
|
||||
|
||||
// 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 dont 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);
|
||||
//log.error("name={}, id ={}, depth={}", compensationRequest.getPayload().getName(), compensationRequest.getPayload().getUid(), depth);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
bsqWalletService.getChainHeightProperty().removeListener(chainHeightListener);
|
||||
if (txConfidenceListener != null)
|
||||
bsqWalletService.removeTxConfidenceListener(txConfidenceListener);
|
||||
|
||||
}
|
||||
|
||||
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.votes.VotesView"
|
||||
hgap="5.0" vgap="5.0"
|
||||
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
|
||||
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="-10.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,50 @@
|
|||
/*
|
||||
* 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.votes;
|
||||
|
||||
import bisq.desktop.common.view.ActivatableView;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import javafx.scene.layout.GridPane;
|
||||
|
||||
@FxmlView
|
||||
public class VotesView extends ActivatableView<GridPane, Void> {
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private VotesView() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
}
|
||||
}
|
|
@ -42,7 +42,8 @@ import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
|||
public class BsqBalanceUtil implements BsqBalanceListener {
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
private TextField availableBalanceTextField, unverifiedBalanceTextField, totalBalanceTextField;
|
||||
private TextField confirmedBalanceTextField, pendingBalanceTextField, lockedForVoteBalanceTextField,
|
||||
totalBalanceTextField;
|
||||
|
||||
@Inject
|
||||
private BsqBalanceUtil(BsqWalletService bsqWalletService,
|
||||
|
@ -52,27 +53,37 @@ public class BsqBalanceUtil implements BsqBalanceListener {
|
|||
}
|
||||
|
||||
public int addGroup(GridPane gridPane, int gridRow) {
|
||||
addTitledGroupBg(gridPane, gridRow, 3, Res.get("shared.balance"));
|
||||
availableBalanceTextField = addLabelTextField(gridPane, gridRow, Res.getWithCol("shared.availableBsqBalance"),
|
||||
addTitledGroupBg(gridPane, gridRow, 4, Res.get("shared.balance"));
|
||||
confirmedBalanceTextField = addLabelTextField(gridPane, gridRow, Res.getWithCol("shared.availableBsqBalance"),
|
||||
Layout.FIRST_ROW_DISTANCE).second;
|
||||
availableBalanceTextField.setMouseTransparent(false);
|
||||
availableBalanceTextField.setMaxWidth(150);
|
||||
availableBalanceTextField.setAlignment(Pos.CENTER_RIGHT);
|
||||
confirmedBalanceTextField.setMouseTransparent(false);
|
||||
confirmedBalanceTextField.setMaxWidth(150);
|
||||
confirmedBalanceTextField.setAlignment(Pos.CENTER_RIGHT);
|
||||
|
||||
unverifiedBalanceTextField = addLabelTextField(gridPane, ++gridRow, Res.getWithCol("shared.unverifiedBsqBalance")).second;
|
||||
unverifiedBalanceTextField.setMouseTransparent(false);
|
||||
unverifiedBalanceTextField.setMaxWidth(availableBalanceTextField.getMaxWidth());
|
||||
unverifiedBalanceTextField.setAlignment(Pos.CENTER_RIGHT);
|
||||
pendingBalanceTextField = addLabelTextField(gridPane, ++gridRow, Res.getWithCol("shared.unverifiedBsqBalance")).second;
|
||||
pendingBalanceTextField.setMouseTransparent(false);
|
||||
pendingBalanceTextField.setMaxWidth(confirmedBalanceTextField.getMaxWidth());
|
||||
pendingBalanceTextField.setAlignment(Pos.CENTER_RIGHT);
|
||||
|
||||
lockedForVoteBalanceTextField = addLabelTextField(gridPane, ++gridRow, Res.getWithCol("shared" +
|
||||
".lockedForVoteBalance")).second;
|
||||
lockedForVoteBalanceTextField.setMouseTransparent(false);
|
||||
lockedForVoteBalanceTextField.setMaxWidth(confirmedBalanceTextField.getMaxWidth());
|
||||
lockedForVoteBalanceTextField.setAlignment(Pos.CENTER_RIGHT);
|
||||
|
||||
totalBalanceTextField = addLabelTextField(gridPane, ++gridRow, Res.getWithCol("shared.totalBsqBalance")).second;
|
||||
totalBalanceTextField.setMouseTransparent(false);
|
||||
totalBalanceTextField.setMaxWidth(availableBalanceTextField.getMaxWidth());
|
||||
totalBalanceTextField.setMaxWidth(confirmedBalanceTextField.getMaxWidth());
|
||||
totalBalanceTextField.setAlignment(Pos.CENTER_RIGHT);
|
||||
|
||||
return gridRow;
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
updateAvailableBalance(bsqWalletService.getAvailableBalance(), bsqWalletService.getUnverifiedBalance());
|
||||
onUpdateBalances(bsqWalletService.getAvailableBalance(),
|
||||
bsqWalletService.getPendingBalance(),
|
||||
bsqWalletService.getLockedForVotingBalance(),
|
||||
bsqWalletService.getLockedInBondsBalance());
|
||||
bsqWalletService.addBsqBalanceListener(this);
|
||||
}
|
||||
|
||||
|
@ -80,10 +91,16 @@ public class BsqBalanceUtil implements BsqBalanceListener {
|
|||
bsqWalletService.removeBsqBalanceListener(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateAvailableBalance(Coin availableBalance, Coin unverifiedBalance) {
|
||||
availableBalanceTextField.setText(bsqFormatter.formatCoinWithCode(availableBalance));
|
||||
unverifiedBalanceTextField.setText(bsqFormatter.formatCoinWithCode(unverifiedBalance));
|
||||
totalBalanceTextField.setText(bsqFormatter.formatCoinWithCode(availableBalance.add(unverifiedBalance)));
|
||||
public void onUpdateBalances(Coin confirmedBalance,
|
||||
Coin pendingBalance,
|
||||
Coin lockedForVotingBalance,
|
||||
Coin lockedInBondsBalance) {
|
||||
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);
|
||||
totalBalanceTextField.setText(bsqFormatter.formatCoinWithCode(total));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ import static bisq.desktop.util.FormBuilder.addLabelInputTextField;
|
|||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
||||
|
||||
@FxmlView
|
||||
public class BsqSendView extends ActivatableView<GridPane, Void> {
|
||||
public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqBalanceListener {
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final WalletsSetup walletsSetup;
|
||||
|
@ -82,7 +82,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> {
|
|||
private Button sendButton;
|
||||
private InputTextField receiversAddressInputTextField;
|
||||
private ChangeListener<Boolean> focusOutListener;
|
||||
private BsqBalanceListener balanceListener;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
|
@ -128,7 +128,8 @@ public class BsqSendView extends ActivatableView<GridPane, Void> {
|
|||
|
||||
focusOutListener = (observable, oldValue, newValue) -> {
|
||||
if (!newValue)
|
||||
verifyInputs();
|
||||
onUpdateBalances(bsqWalletService.getAvailableBalance(), bsqWalletService.getPendingBalance(),
|
||||
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance());
|
||||
};
|
||||
|
||||
sendButton = addButtonAfterGroup(root, ++gridRow, Res.get("dao.wallet.send.send"));
|
||||
|
@ -198,8 +199,6 @@ public class BsqSendView extends ActivatableView<GridPane, Void> {
|
|||
GUIUtil.showNotReadyForTxBroadcastPopups(p2PService, walletsSetup);
|
||||
}
|
||||
});
|
||||
|
||||
balanceListener = (availableBalance, unverifiedBalance) -> verifyInputs();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -207,8 +206,9 @@ public class BsqSendView extends ActivatableView<GridPane, Void> {
|
|||
bsqBalanceUtil.activate();
|
||||
receiversAddressInputTextField.focusedProperty().addListener(focusOutListener);
|
||||
amountInputTextField.focusedProperty().addListener(focusOutListener);
|
||||
bsqWalletService.addBsqBalanceListener(balanceListener);
|
||||
verifyInputs();
|
||||
bsqWalletService.addBsqBalanceListener(this);
|
||||
onUpdateBalances(bsqWalletService.getAvailableBalance(), bsqWalletService.getPendingBalance(),
|
||||
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -216,11 +216,15 @@ public class BsqSendView extends ActivatableView<GridPane, Void> {
|
|||
bsqBalanceUtil.deactivate();
|
||||
receiversAddressInputTextField.focusedProperty().removeListener(focusOutListener);
|
||||
amountInputTextField.focusedProperty().removeListener(focusOutListener);
|
||||
bsqWalletService.removeBsqBalanceListener(balanceListener);
|
||||
bsqWalletService.removeBsqBalanceListener(this);
|
||||
}
|
||||
|
||||
private void verifyInputs() {
|
||||
bsqValidator.setAvailableBalance(bsqWalletService.getAvailableBalance());
|
||||
@Override
|
||||
public void onUpdateBalances(Coin confirmedBalance,
|
||||
Coin pendingBalance,
|
||||
Coin lockedForVotingBalance,
|
||||
Coin lockedInBondsBalance) {
|
||||
bsqValidator.setAvailableBalance(confirmedBalance);
|
||||
boolean isValid = bsqAddressValidator.validate(receiversAddressInputTextField.getText()).isValid &&
|
||||
bsqValidator.validate(amountInputTextField.getText()).isValid;
|
||||
sendButton.setDisable(!isValid);
|
||||
|
|
|
@ -40,6 +40,7 @@ import bisq.core.dao.node.BsqNodeProvider;
|
|||
import bisq.core.locale.Res;
|
||||
import bisq.core.user.Preferences;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -78,7 +79,7 @@ import java.util.Set;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
@FxmlView
|
||||
public class BsqTxView extends ActivatableView<GridPane, Void> {
|
||||
public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBalanceListener {
|
||||
|
||||
TableView<BsqTxListItem> tableView;
|
||||
private Pane rootParent;
|
||||
|
@ -99,7 +100,6 @@ public class BsqTxView extends ActivatableView<GridPane, Void> {
|
|||
private int gridRow = 0;
|
||||
private Label chainHeightLabel;
|
||||
private BsqBlockChainListener bsqBlockChainListener;
|
||||
private BsqBalanceListener bsqBalanceListener;
|
||||
private ProgressBar chainSyncIndicator;
|
||||
private ChangeListener<Number> chainHeightChangedListener;
|
||||
|
||||
|
@ -162,7 +162,6 @@ public class BsqTxView extends ActivatableView<GridPane, Void> {
|
|||
root.getChildren().add(vBox);
|
||||
|
||||
walletBsqTransactionsListener = change -> updateList();
|
||||
bsqBalanceListener = (availableBalance, unverifiedBalance) -> updateList();
|
||||
parentHeightListener = (observable, oldValue, newValue) -> layout();
|
||||
bsqBlockChainListener = this::onChainHeightChanged;
|
||||
chainHeightChangedListener = (observable, oldValue, newValue) -> onChainHeightChanged();
|
||||
|
@ -172,7 +171,7 @@ public class BsqTxView extends ActivatableView<GridPane, Void> {
|
|||
protected void activate() {
|
||||
bsqBalanceUtil.activate();
|
||||
bsqWalletService.getWalletTransactions().addListener(walletBsqTransactionsListener);
|
||||
bsqWalletService.addBsqBalanceListener(bsqBalanceListener);
|
||||
bsqWalletService.addBsqBalanceListener(this);
|
||||
btcWalletService.getChainHeightProperty().addListener(chainHeightChangedListener);
|
||||
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
|
@ -195,7 +194,7 @@ public class BsqTxView extends ActivatableView<GridPane, Void> {
|
|||
bsqBalanceUtil.deactivate();
|
||||
sortedList.comparatorProperty().unbind();
|
||||
bsqWalletService.getWalletTransactions().removeListener(walletBsqTransactionsListener);
|
||||
bsqWalletService.removeBsqBalanceListener(bsqBalanceListener);
|
||||
bsqWalletService.removeBsqBalanceListener(this);
|
||||
btcWalletService.getChainHeightProperty().removeListener(chainHeightChangedListener);
|
||||
bsqNode.removeBsqBlockChainListener(bsqBlockChainListener);
|
||||
|
||||
|
@ -205,6 +204,14 @@ public class BsqTxView extends ActivatableView<GridPane, Void> {
|
|||
rootParent.heightProperty().removeListener(parentHeightListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateBalances(Coin confirmedBalance,
|
||||
Coin pendingBalance,
|
||||
Coin lockedForVotingBalance,
|
||||
Coin lockedInBondsBalance) {
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void onChainHeightChanged() {
|
||||
final int bsqWalletChainHeight = bsqWalletService.getChainHeightProperty().get();
|
||||
final int bsqBlockChainHeight = bsqBlockChain.getChainHeadHeight();
|
||||
|
@ -558,6 +565,5 @@ public class BsqTxView extends ActivatableView<GridPane, Void> {
|
|||
GUIUtil.openWebPage(preferences.getBsqBlockChainExplorer().addressUrl + item.getAddress());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
* Note that the create offer domain has a deeper scope in the application domain (TradeManager).
|
||||
* That model is just responsible for the domain specific parts displayed needed in that UI element.
|
||||
*/
|
||||
class CreateOfferDataModel extends OfferDataModel {
|
||||
class CreateOfferDataModel extends OfferDataModel implements BsqBalanceListener {
|
||||
private final OpenOfferManager openOfferManager;
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final Preferences preferences;
|
||||
|
@ -114,7 +114,6 @@ class CreateOfferDataModel extends OfferDataModel {
|
|||
private final BSFormatter formatter;
|
||||
private final String offerId;
|
||||
private final BalanceListener btcBalanceListener;
|
||||
private final BsqBalanceListener bsqBalanceListener;
|
||||
private final SetChangeListener<PaymentAccount> paymentAccountsChangeListener;
|
||||
|
||||
private OfferPayload.Direction direction;
|
||||
|
@ -206,8 +205,6 @@ class CreateOfferDataModel extends OfferDataModel {
|
|||
}
|
||||
};
|
||||
|
||||
bsqBalanceListener = (availableBalance, unverifiedBalance) -> updateBalance();
|
||||
|
||||
paymentAccountsChangeListener = change -> fillPaymentAccounts();
|
||||
}
|
||||
|
||||
|
@ -229,7 +226,7 @@ class CreateOfferDataModel extends OfferDataModel {
|
|||
private void addListeners() {
|
||||
btcWalletService.addBalanceListener(btcBalanceListener);
|
||||
if (BisqEnvironment.isBaseCurrencySupportingBsq())
|
||||
bsqWalletService.addBsqBalanceListener(bsqBalanceListener);
|
||||
bsqWalletService.addBsqBalanceListener(this);
|
||||
user.getPaymentAccountsAsObservable().addListener(paymentAccountsChangeListener);
|
||||
}
|
||||
|
||||
|
@ -237,7 +234,7 @@ class CreateOfferDataModel extends OfferDataModel {
|
|||
private void removeListeners() {
|
||||
btcWalletService.removeBalanceListener(btcBalanceListener);
|
||||
if (BisqEnvironment.isBaseCurrencySupportingBsq())
|
||||
bsqWalletService.removeBsqBalanceListener(bsqBalanceListener);
|
||||
bsqWalletService.removeBsqBalanceListener(this);
|
||||
user.getPaymentAccountsAsObservable().removeListener(paymentAccountsChangeListener);
|
||||
}
|
||||
|
||||
|
@ -544,6 +541,14 @@ class CreateOfferDataModel extends OfferDataModel {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateBalances(Coin confirmedBalance,
|
||||
Coin pendingBalance,
|
||||
Coin lockedForVotingBalance,
|
||||
Coin lockedInBondsBalance) {
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
void fundFromSavingsWallet() {
|
||||
this.useSavingsWallet = true;
|
||||
updateBalance();
|
||||
|
|
|
@ -539,7 +539,7 @@ public class GUIUtil {
|
|||
childByRowMap.get(rowIndex).add(child);
|
||||
});
|
||||
|
||||
for (int i = start; i < end; i++) {
|
||||
for (int i = Math.min(start, childByRowMap.size()); i < Math.min(end, childByRowMap.size()); i++) {
|
||||
childByRowMap.get(i).forEach(child -> gridPane.getChildren().remove(child));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue